354 lines
12 KiB
C#
354 lines
12 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
|
|
namespace Flee.InternalTypes
|
|
{
|
|
/// <summary>
|
|
/// 包含各种共享实用方法的工具类
|
|
/// </summary>
|
|
internal class Utility
|
|
{
|
|
private Utility()
|
|
{
|
|
}
|
|
|
|
public static void AssertNotNull(object o, string paramName)
|
|
{
|
|
if (o == null)
|
|
{
|
|
throw new ArgumentNullException(paramName);
|
|
}
|
|
}
|
|
|
|
public static void EmitStoreLocal(FleeILGenerator ilg, int index)
|
|
{
|
|
if (index >= 0 & index <= 3)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
ilg.Emit(OpCodes.Stloc_0);
|
|
break;
|
|
case 1:
|
|
ilg.Emit(OpCodes.Stloc_1);
|
|
break;
|
|
case 2:
|
|
ilg.Emit(OpCodes.Stloc_2);
|
|
break;
|
|
case 3:
|
|
ilg.Emit(OpCodes.Stloc_3);
|
|
break;
|
|
}
|
|
}
|
|
else if (index < 256)
|
|
{
|
|
ilg.Emit(OpCodes.Stloc_S, Convert.ToByte(index));
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(index < 65535, "local index too large");
|
|
ilg.Emit(OpCodes.Stloc, unchecked((short)Convert.ToUInt16(index)));
|
|
}
|
|
}
|
|
|
|
public static void EmitLoadLocal(FleeILGenerator ilg, int index)
|
|
{
|
|
Debug.Assert(index >= 0, "Invalid index");
|
|
|
|
if (index >= 0 & index <= 3)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
ilg.Emit(OpCodes.Ldloc_0);
|
|
break;
|
|
case 1:
|
|
ilg.Emit(OpCodes.Ldloc_1);
|
|
break;
|
|
case 2:
|
|
ilg.Emit(OpCodes.Ldloc_2);
|
|
break;
|
|
case 3:
|
|
ilg.Emit(OpCodes.Ldloc_3);
|
|
break;
|
|
}
|
|
}
|
|
else if (index < 256)
|
|
{
|
|
ilg.Emit(OpCodes.Ldloc_S, Convert.ToByte(index));
|
|
}
|
|
else
|
|
{
|
|
Debug.Assert(index < 65535, "local index too large");
|
|
ilg.Emit(OpCodes.Ldloc, unchecked((short)Convert.ToUInt16(index)));
|
|
}
|
|
}
|
|
|
|
public static void EmitLoadLocalAddress(FleeILGenerator ilg, int index)
|
|
{
|
|
Debug.Assert(index >= 0, "Invalid index");
|
|
|
|
if (index <= byte.MaxValue)
|
|
{
|
|
ilg.Emit(OpCodes.Ldloca_S, Convert.ToByte(index));
|
|
}
|
|
else
|
|
{
|
|
ilg.Emit(OpCodes.Ldloca, index);
|
|
}
|
|
}
|
|
|
|
public static void EmitArrayLoad(FleeILGenerator ilg, Type elementType)
|
|
{
|
|
TypeCode tc = Type.GetTypeCode(elementType);
|
|
|
|
switch (tc)
|
|
{
|
|
case TypeCode.Byte:
|
|
ilg.Emit(OpCodes.Ldelem_U1);
|
|
break;
|
|
case TypeCode.SByte:
|
|
case TypeCode.Boolean:
|
|
ilg.Emit(OpCodes.Ldelem_I1);
|
|
break;
|
|
case TypeCode.Int16:
|
|
ilg.Emit(OpCodes.Ldelem_I2);
|
|
break;
|
|
case TypeCode.UInt16:
|
|
ilg.Emit(OpCodes.Ldelem_U2);
|
|
break;
|
|
case TypeCode.Int32:
|
|
ilg.Emit(OpCodes.Ldelem_I4);
|
|
break;
|
|
case TypeCode.UInt32:
|
|
ilg.Emit(OpCodes.Ldelem_U4);
|
|
break;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
ilg.Emit(OpCodes.Ldelem_I8);
|
|
break;
|
|
case TypeCode.Single:
|
|
ilg.Emit(OpCodes.Ldelem_R4);
|
|
break;
|
|
case TypeCode.Double:
|
|
ilg.Emit(OpCodes.Ldelem_R8);
|
|
break;
|
|
case TypeCode.Object:
|
|
case TypeCode.String:
|
|
ilg.Emit(OpCodes.Ldelem_Ref);
|
|
break;
|
|
default:
|
|
// Must be a non-primitive value type
|
|
ilg.Emit(OpCodes.Ldelema, elementType);
|
|
ilg.Emit(OpCodes.Ldobj, elementType);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public static void EmitArrayStore(FleeILGenerator ilg, Type elementType)
|
|
{
|
|
TypeCode tc = Type.GetTypeCode(elementType);
|
|
|
|
switch (tc)
|
|
{
|
|
case TypeCode.Byte:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Boolean:
|
|
ilg.Emit(OpCodes.Stelem_I1);
|
|
break;
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
ilg.Emit(OpCodes.Stelem_I2);
|
|
break;
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
ilg.Emit(OpCodes.Stelem_I4);
|
|
break;
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
ilg.Emit(OpCodes.Stelem_I8);
|
|
break;
|
|
case TypeCode.Single:
|
|
ilg.Emit(OpCodes.Stelem_R4);
|
|
break;
|
|
case TypeCode.Double:
|
|
ilg.Emit(OpCodes.Stelem_R8);
|
|
break;
|
|
case TypeCode.Object:
|
|
case TypeCode.String:
|
|
ilg.Emit(OpCodes.Stelem_Ref);
|
|
break;
|
|
default:
|
|
// Must be a non-primitive value type
|
|
ilg.Emit(OpCodes.Stelem, elementType);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static bool IsIntegralType(Type t)
|
|
{
|
|
TypeCode tc = Type.GetTypeCode(t);
|
|
switch (tc)
|
|
{
|
|
case TypeCode.Byte:
|
|
case TypeCode.SByte:
|
|
case TypeCode.Int16:
|
|
case TypeCode.UInt16:
|
|
case TypeCode.Int32:
|
|
case TypeCode.UInt32:
|
|
case TypeCode.Int64:
|
|
case TypeCode.UInt64:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static Type GetBitwiseOpType(Type leftType, Type rightType)
|
|
{
|
|
if (IsIntegralType(leftType) == false || IsIntegralType(rightType) == false)
|
|
{
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
return ImplicitConverter.GetBinaryResultType(leftType, rightType);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Find a simple (unary) overloaded operator
|
|
/// </summary>
|
|
/// <param name="name">The name of the operator</param>
|
|
/// <param name="sourceType">The type to convert from</param>
|
|
/// <param name="destType">The type to convert to (can be null if it's not known beforehand)</param>
|
|
/// <returns>The operator's method or null of no match is found</returns>
|
|
public static MethodInfo GetSimpleOverloadedOperator(string name, Type sourceType, Type destType)
|
|
{
|
|
Hashtable data = new Hashtable();
|
|
data.Add("Name", string.Concat("op_", name));
|
|
data.Add("sourceType", sourceType);
|
|
data.Add("destType", destType);
|
|
|
|
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
|
|
|
|
// Look on the source type and its ancestors
|
|
MemberInfo[] members = new MemberInfo[0];
|
|
do
|
|
{
|
|
members = sourceType.FindMembers(MemberTypes.Method, flags, SimpleOverloadedOperatorFilter, data);
|
|
} while (members.Length == 0 && (sourceType = sourceType.BaseType) != null);
|
|
|
|
if (members.Length == 0 && destType != null)
|
|
{
|
|
// Look on the dest type and its ancestors
|
|
do
|
|
{
|
|
members = destType.FindMembers(MemberTypes.Method, flags, SimpleOverloadedOperatorFilter, data);
|
|
} while (members.Length == 0 && (destType = destType.BaseType) != null);
|
|
}
|
|
|
|
Debug.Assert(members.Length < 2, "Multiple overloaded operators found");
|
|
|
|
if (members.Length == 0)
|
|
{
|
|
// No match
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
return (MethodInfo)members[0];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Matches simple overloaded operators
|
|
/// </summary>
|
|
/// <param name="member"></param>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
/// <remarks></remarks>
|
|
private static bool SimpleOverloadedOperatorFilter(MemberInfo member, object value)
|
|
{
|
|
IDictionary data = (IDictionary)value;
|
|
MethodInfo method = (MethodInfo)member;
|
|
|
|
bool nameMatch = method.IsSpecialName == true && method.Name.Equals((string)data["Name"], StringComparison.OrdinalIgnoreCase);
|
|
|
|
if (nameMatch == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// destination type might not be known
|
|
Type destType = (Type)data["destType"];
|
|
|
|
if (destType != null)
|
|
{
|
|
bool returnTypeMatch = object.ReferenceEquals(destType, method.ReturnType);
|
|
|
|
if (returnTypeMatch == false)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ParameterInfo[] parameters = method.GetParameters();
|
|
bool argumentMatch = parameters.Length > 0 && parameters[0].ParameterType.IsAssignableFrom((Type)data["sourceType"]);
|
|
|
|
return argumentMatch;
|
|
}
|
|
|
|
public static MethodInfo GetOverloadedOperator(string name, Type sourceType, Binder binder, params Type[] argumentTypes)
|
|
{
|
|
name = string.Concat("op_", name);
|
|
MethodInfo mi = null;
|
|
do
|
|
{
|
|
mi = sourceType.GetMethod(name, BindingFlags.Public | BindingFlags.Static, binder, CallingConventions.Any, argumentTypes, null);
|
|
if (mi != null && mi.IsSpecialName == true)
|
|
{
|
|
return mi;
|
|
}
|
|
} while ((sourceType = sourceType.BaseType) != null);
|
|
|
|
return null;
|
|
}
|
|
|
|
public static int GetILGeneratorLength(ILGenerator ilg)
|
|
{
|
|
//System.Reflection.FieldInfo fi = typeof(ILGenerator).GetField("m_length", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
//return (int)fi.GetValue(ilg);
|
|
return ilg.ILOffset;
|
|
}
|
|
|
|
public static bool IsLongBranch(int startPosition, int endPosition)
|
|
{
|
|
return (endPosition - startPosition) > sbyte.MaxValue;
|
|
}
|
|
|
|
public static string FormatList(string[] items)
|
|
{
|
|
string separator = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator + " ";
|
|
return string.Join(separator, items);
|
|
}
|
|
|
|
public static string GetGeneralErrorMessage(string key, params object[] args)
|
|
{
|
|
string msg = $"{key}";
|
|
return $"[{msg}]{string.Join(',',args)}";
|
|
}
|
|
|
|
public static string GetCompileErrorMessage(string key, params object[] args)
|
|
{
|
|
string msg = $"{key}";
|
|
return $"[{msg}]{string.Join(',', args)}";
|
|
}
|
|
}
|
|
}
|