Files
Flee/ExpressionElements/Base/Binary.cs

163 lines
6.0 KiB
C#

using System.Collections;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Reflection;
using Flee.InternalTypes;
using Flee.PublicTypes;
using System;
namespace Flee.ExpressionElements.Base
{
/// <summary>
/// 操作两个子元素的表达式元素的基类
/// </summary>
internal abstract class BinaryExpressionElement : ExpressionElement
{
protected ExpressionElement MyLeftChild;
protected ExpressionElement MyRightChild;
private Type _myResultType;
protected BinaryExpressionElement()
{
}
/// <summary>
/// Converts a list of binary elements into a binary tree
/// </summary>
/// <param name="childValues"></param>
/// <param name="elementType"></param>
/// <returns></returns>
public static BinaryExpressionElement CreateElement(IList childValues, Type elementType)
{
BinaryExpressionElement firstElement = (BinaryExpressionElement)Activator.CreateInstance(elementType);
firstElement.Configure((ExpressionElement)childValues[0], (ExpressionElement)childValues[2], childValues[1]);
BinaryExpressionElement lastElement = firstElement;
for (int i = 3; i <= childValues.Count - 1; i += 2)
{
BinaryExpressionElement element = (BinaryExpressionElement)Activator.CreateInstance(elementType);
element.Configure(lastElement, (ExpressionElement)childValues[i + 1], childValues[i]);
lastElement = element;
}
return lastElement;
}
protected abstract void GetOperation(object operation);
protected void ValidateInternal(object op)
{
_myResultType = this.GetResultType(MyLeftChild.ResultType, MyRightChild.ResultType);
if (_myResultType == null)
{
this.ThrowOperandTypeMismatch(op, MyLeftChild.ResultType, MyRightChild.ResultType);
}
}
protected MethodInfo GetOverloadedBinaryOperator(string name, object operation)
{
Type leftType = MyLeftChild.ResultType;
Type rightType = MyRightChild.ResultType;
BinaryOperatorBinder binder = new BinaryOperatorBinder(leftType, rightType);
// If both arguments are of the same type, pick either as the owner type
if (object.ReferenceEquals(leftType, rightType))
{
return Utility.GetOverloadedOperator(name, leftType, binder, leftType, rightType);
}
// Get the operator for both types
MethodInfo leftMethod = default(MethodInfo);
MethodInfo rightMethod = default(MethodInfo);
leftMethod = Utility.GetOverloadedOperator(name, leftType, binder, leftType, rightType);
rightMethod = Utility.GetOverloadedOperator(name, rightType, binder, leftType, rightType);
// Pick the right one
if (leftMethod == null & rightMethod == null)
{
// No operator defined for either
return null;
}
else if (leftMethod == null)
{
return rightMethod;
}
else if (rightMethod == null)
{
return leftMethod;
}
else if (object.ReferenceEquals(leftMethod, rightMethod))
{
// same operator for both (most likely defined in a common base class)
return leftMethod;
}
else
{
// Ambiguous call
base.ThrowAmbiguousCallException(leftType, rightType, operation);
return null;
}
}
protected void EmitOverloadedOperatorCall(MethodInfo method, FleeILGenerator ilg, IServiceProvider services)
{
ParameterInfo[] @params = method.GetParameters();
ParameterInfo pLeft = @params[0];
ParameterInfo pRight = @params[1];
EmitChildWithConvert(MyLeftChild, pLeft.ParameterType, ilg, services);
EmitChildWithConvert(MyRightChild, pRight.ParameterType, ilg, services);
ilg.Emit(OpCodes.Call, method);
}
protected void ThrowOperandTypeMismatch(object operation, Type leftType, Type rightType)
{
base.ThrowCompileException("OperationNotDefinedForTypes", CompileExceptionReason.TypeMismatch, operation, leftType.Name, rightType.Name);
}
protected abstract Type GetResultType(Type leftType, Type rightType);
protected static void EmitChildWithConvert(ExpressionElement child, Type resultType, FleeILGenerator ilg, IServiceProvider services)
{
child.Emit(ilg, services);
bool converted = ImplicitConverter.EmitImplicitConvert(child.ResultType, resultType, ilg);
Debug.Assert(converted, "convert failed");
}
protected bool AreBothChildrenOfType(Type target)
{
return IsChildOfType(MyLeftChild, target) & IsChildOfType(MyRightChild, target);
}
protected bool IsEitherChildOfType(Type target)
{
return IsChildOfType(MyLeftChild, target) || IsChildOfType(MyRightChild, target);
}
protected static bool IsChildOfType(ExpressionElement child, Type t)
{
return object.ReferenceEquals(child.ResultType, t);
}
/// <summary>
/// Set the left and right operands, get the operation, and get the result type
/// </summary>
/// <param name="leftChild"></param>
/// <param name="rightChild"></param>
/// <param name="op"></param>
private void Configure(ExpressionElement leftChild, ExpressionElement rightChild, object op)
{
MyLeftChild = leftChild;
MyRightChild = rightChild;
this.GetOperation(op);
this.ValidateInternal(op);
}
public sealed override System.Type ResultType => _myResultType;
}
}