' This library is free software; you can redistribute it and/or
' modify it under the terms of the GNU Lesser General Public License
' as published by the Free Software Foundation; either version 2.1
' of the License, or (at your option) any later version.
'
' This library is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
' Lesser General Public License for more details.
'
' You should have received a copy of the GNU Lesser General Public
' License along with this library; if not, write to the Free
' Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
' MA 02111-1307, USA.
'
' Flee - Fast Lightweight Expression Evaluator
' Copyright © 2007 Eugene Ciloci
'
Imports System.Reflection
Imports System.Reflection.Emit
'''
''' Holds various shared utility methods
'''
'''
Friend Class Utility
Private Sub New()
End Sub
Public Shared Sub AssertNotNull(ByVal o As Object, ByVal paramName As String)
If o Is Nothing Then
Throw New ArgumentNullException(paramName)
End If
End Sub
Public Shared Sub EmitStoreLocal(ByVal ilg As FleeILGenerator, ByVal index As Integer)
If index >= 0 And index <= 3 Then
Select Case index
Case 0
ilg.Emit(OpCodes.Stloc_0)
Case 1
ilg.Emit(OpCodes.Stloc_1)
Case 2
ilg.Emit(OpCodes.Stloc_2)
Case 3
ilg.Emit(OpCodes.Stloc_3)
End Select
Else
Debug.Assert(index < 256, "local index too large")
ilg.Emit(OpCodes.Stloc_S, CByte(index))
End If
End Sub
Public Shared Sub EmitLoadLocal(ByVal ilg As FleeILGenerator, ByVal index As Integer)
Debug.Assert(index >= 0, "Invalid index")
If index >= 0 And index <= 3 Then
Select Case index
Case 0
ilg.Emit(OpCodes.Ldloc_0)
Case 1
ilg.Emit(OpCodes.Ldloc_1)
Case 2
ilg.Emit(OpCodes.Ldloc_2)
Case 3
ilg.Emit(OpCodes.Ldloc_3)
End Select
Else
Debug.Assert(index < 256, "local index too large")
ilg.Emit(OpCodes.Ldloc_S, CByte(index))
End If
End Sub
Public Shared Sub EmitLoadLocalAddress(ByVal ilg As FleeILGenerator, ByVal index As Integer)
Debug.Assert(index >= 0, "Invalid index")
If index <= Byte.MaxValue Then
ilg.Emit(OpCodes.Ldloca_S, CByte(index))
Else
ilg.Emit(OpCodes.Ldloca, index)
End If
End Sub
Public Shared Sub EmitArrayLoad(ByVal ilg As FleeILGenerator, ByVal elementType As Type)
Dim tc As TypeCode = Type.GetTypeCode(elementType)
Select Case tc
Case TypeCode.Byte
ilg.Emit(OpCodes.Ldelem_U1)
Case TypeCode.SByte, TypeCode.Boolean
ilg.Emit(OpCodes.Ldelem_I1)
Case TypeCode.Int16
ilg.Emit(OpCodes.Ldelem_I2)
Case TypeCode.UInt16
ilg.Emit(OpCodes.Ldelem_U2)
Case TypeCode.Int32
ilg.Emit(OpCodes.Ldelem_I4)
Case TypeCode.UInt32
ilg.Emit(OpCodes.Ldelem_U4)
Case TypeCode.Int64, TypeCode.UInt64
ilg.Emit(OpCodes.Ldelem_I8)
Case TypeCode.Single
ilg.Emit(OpCodes.Ldelem_R4)
Case TypeCode.Double
ilg.Emit(OpCodes.Ldelem_R8)
Case TypeCode.Object, TypeCode.String
ilg.Emit(OpCodes.Ldelem_Ref)
Case Else
' Must be a non-primitive value type
ilg.Emit(OpCodes.Ldelema, elementType)
ilg.Emit(OpCodes.Ldobj, elementType)
Return
End Select
End Sub
Public Shared Sub EmitArrayStore(ByVal ilg As FleeILGenerator, ByVal elementType As Type)
Dim tc As TypeCode = Type.GetTypeCode(elementType)
Select Case tc
Case TypeCode.Byte, TypeCode.SByte, TypeCode.Boolean
ilg.Emit(OpCodes.Stelem_I1)
Case TypeCode.Int16, TypeCode.UInt16
ilg.Emit(OpCodes.Stelem_I2)
Case TypeCode.Int32, TypeCode.UInt32
ilg.Emit(OpCodes.Stelem_I4)
Case TypeCode.Int64, TypeCode.UInt64
ilg.Emit(OpCodes.Stelem_I8)
Case TypeCode.Single
ilg.Emit(OpCodes.Stelem_R4)
Case TypeCode.Double
ilg.Emit(OpCodes.Stelem_R8)
Case TypeCode.Object, TypeCode.String
ilg.Emit(OpCodes.Stelem_Ref)
Case Else
' Must be a non-primitive value type
ilg.Emit(OpCodes.Stelem, elementType)
End Select
End Sub
Public Shared Sub SyncFleeILGeneratorLabels(ByVal source As FleeILGenerator, ByVal target As FleeILGenerator)
While source.LabelCount <> target.LabelCount
target.DefineLabel()
End While
End Sub
Public Shared Function IsIntegralType(ByVal t As Type) As Boolean
Dim tc As TypeCode = Type.GetTypeCode(t)
Select Case tc
Case TypeCode.Byte, TypeCode.SByte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64
Return True
Case Else
Return False
End Select
End Function
Public Shared Function GetBitwiseOpType(ByVal leftType As Type, ByVal rightType As Type) As Type
If IsIntegralType(leftType) = False OrElse IsIntegralType(rightType) = False Then
Return Nothing
Else
Return ImplicitConverter.GetBinaryResultType(leftType, rightType)
End If
End Function
'''
''' Find a simple (unary) overloaded operator
'''
''' The name of the operator
''' The type to convert from
''' The type to convert to
''' The operator's method or null of no match is found
Public Shared Function GetSimpleOverloadedOperator(ByVal name As String, ByVal sourceType As Type, ByVal destType As Type) As MethodInfo
Dim data As New Hashtable()
data.Add("Name", String.Concat("op_", name))
data.Add("sourceType", sourceType)
data.Add("destType", destType)
Const flags As BindingFlags = BindingFlags.Public Or BindingFlags.Static
' Look on the source type
Dim members As MemberInfo() = sourceType.FindMembers(MemberTypes.Method, flags, AddressOf SimpleOverloadedOperatorFilter, data)
If members.Length = 0 Then
' Look on the dest type
members = destType.FindMembers(MemberTypes.Method, flags, AddressOf SimpleOverloadedOperatorFilter, data)
End If
Debug.Assert(members.Length < 2, "Multiple overloaded operators found")
If members.Length = 0 Then
' No match
Return Nothing
Else
Return members(0)
End If
End Function
'''
''' Matches simple overloaded operators
'''
'''
'''
'''
'''
Private Shared Function SimpleOverloadedOperatorFilter(ByVal member As MemberInfo, ByVal value As Object) As Boolean
Dim data As IDictionary = value
Dim method As MethodInfo = DirectCast(member, MethodInfo)
Dim nameMatch As Boolean = method.IsSpecialName = True AndAlso method.Name.Equals(DirectCast(data("Name"), String), StringComparison.OrdinalIgnoreCase)
If nameMatch = False Then
Return False
End If
Dim returnTypeMatch As Boolean = method.ReturnType Is DirectCast(data("destType"), Type)
If returnTypeMatch = False Then
Return False
End If
Dim parameters As ParameterInfo() = method.GetParameters()
Dim argumentMatch As Boolean = parameters.Length > 0 AndAlso parameters(0).ParameterType Is DirectCast(data("sourceType"), Type)
Return argumentMatch
End Function
Public Shared Function GetOverloadedOperator(ByVal name As String, ByVal sourceType As Type, ByVal binder As Binder, ByVal ParamArray argumentTypes As Type()) As MethodInfo
name = String.Concat("op_", name)
Dim mi As MethodInfo = sourceType.GetMethod(name, BindingFlags.Public Or BindingFlags.Static, binder, CallingConventions.Any, argumentTypes, Nothing)
If mi Is Nothing OrElse mi.IsSpecialName = False Then
Return Nothing
Else
Return mi
End If
End Function
Public Shared Function GetILGeneratorLength(ByVal ilg As ILGenerator) As Integer
Dim fi As System.Reflection.FieldInfo = GetType(ILGenerator).GetField("m_length", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
Return DirectCast(fi.GetValue(ilg), Integer)
End Function
Public Shared Function IsLongBranch(ByVal startPosition As Integer, ByVal endPosition As Integer) As Boolean
Return (endPosition - startPosition) > SByte.MaxValue
End Function
Public Shared Function FormatList(ByVal items As String()) As String
Dim separator As String = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator + " "
Return String.Join(separator, items)
End Function
Public Shared Function GetGeneralErrorMessage(ByVal key As String, ByVal ParamArray args As Object()) As String
Dim msg As String = FleeResourceManager.Instance.GetGeneralErrorString(key)
Return String.Format(msg, args)
End Function
Public Shared Function GetCompileErrorMessage(ByVal key As String, ByVal ParamArray args As Object()) As String
Dim msg As String = FleeResourceManager.Instance.GetCompileErrorString(key)
Return String.Format(msg, args)
End Function
End Class