336 lines
12 KiB
VB.net
336 lines
12 KiB
VB.net
#Region "Microsoft.VisualBasic::a94e940d251c96dc1bdeab9171871900, Microsoft.VisualBasic.Core\Language\Linq\Vectorization\SchemaProvider.vb"
|
||
|
||
' Author:
|
||
'
|
||
' asuka (amethyst.asuka@gcmodeller.org)
|
||
' xie (genetics@smrucc.org)
|
||
' xieguigang (xie.guigang@live.com)
|
||
'
|
||
' Copyright (c) 2018 GPL3 Licensed
|
||
'
|
||
'
|
||
' GNU GENERAL PUBLIC LICENSE (GPL3)
|
||
'
|
||
'
|
||
' This program is free software: you can redistribute it and/or modify
|
||
' it under the terms of the GNU General Public License as published by
|
||
' the Free Software Foundation, either version 3 of the License, or
|
||
' (at your option) any later version.
|
||
'
|
||
' This program 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 General Public License for more details.
|
||
'
|
||
' You should have received a copy of the GNU General Public License
|
||
' along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
|
||
|
||
' /********************************************************************************/
|
||
|
||
' Summaries:
|
||
|
||
' Class VectorSchemaProvider
|
||
'
|
||
' Properties: PropertyNames, Type
|
||
'
|
||
' Constructor: (+1 Overloads) Sub New
|
||
' Function: [Concatenate], [IntegerDivision], [Like], binaryOperatorSelfLeft, GetDynamicMemberNames
|
||
' ToString, TryBinaryOperation, (+2 Overloads) TryGetMember, TryInvokeMember, TrySetMember
|
||
' TryUnaryOperation
|
||
'
|
||
'
|
||
' /********************************************************************************/
|
||
|
||
#End Region
|
||
|
||
Imports System.Dynamic
|
||
Imports System.Linq.Expressions
|
||
Imports System.Reflection
|
||
Imports Microsoft.VisualBasic.ComponentModel.Collection
|
||
Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
|
||
Imports Microsoft.VisualBasic.Emit.Delegates
|
||
Imports Microsoft.VisualBasic.Linq
|
||
Imports Microsoft.VisualBasic.Scripting.Runtime
|
||
Imports Microsoft.VisualBasic.Scripting.TokenIcer
|
||
|
||
Namespace Language.Vectorization
|
||
|
||
''' <summary>
|
||
''' Schema provider of the <see cref="VectorShadows(Of T)"/>
|
||
''' </summary>
|
||
Public Class VectorSchemaProvider
|
||
|
||
''' <summary>
|
||
''' 单目运算符无重名的问题
|
||
''' </summary>
|
||
ReadOnly operatorsUnary As New Dictionary(Of ExpressionType, MethodInfo)
|
||
''' <summary>
|
||
''' 双目运算符重载会带来重名运算符的问题
|
||
''' </summary>
|
||
ReadOnly operatorsBinary As New Dictionary(Of ExpressionType, BinaryOperator)
|
||
|
||
#Region "VisualBasic exclusive language features"
|
||
ReadOnly op_Concatenates As BinaryOperator
|
||
ReadOnly op_Likes As BinaryOperator
|
||
ReadOnly op_IntegerDivisions As BinaryOperator
|
||
#End Region
|
||
|
||
''' <summary>
|
||
''' The overloads function
|
||
''' </summary>
|
||
ReadOnly methods As New Dictionary(Of String, OverloadsFunction)
|
||
ReadOnly propertyList As Dictionary(Of String, PropertyInfo)
|
||
|
||
Public ReadOnly Property PropertyNames As Index(Of String)
|
||
Public ReadOnly Property Type As Type
|
||
|
||
Public Const stringContract$ = "op_Concatenate"
|
||
Public Const objectLike$ = "op_Like"
|
||
Public Const nameIntegerDivision$ = "op_IntegerDivision"
|
||
|
||
Sub New(type As Type)
|
||
Me.Type = type
|
||
Me.propertyList = type.Schema(PropertyAccess.NotSure, PublicProperty, True)
|
||
Me.PropertyNames = propertyList _
|
||
.Values _
|
||
.Select(Function([property]) [property].Name) _
|
||
.Indexing
|
||
|
||
Dim methods = type.GetMethods()
|
||
Dim operators = methods _
|
||
.Where(Function(x) InStr(x.Name, "op_") = 1 AndAlso x.IsStatic) _
|
||
.GroupBy(Function(op) op.Name) _
|
||
.ToArray
|
||
|
||
Dim find = Function(opName$)
|
||
Return operators _
|
||
.Where(Function(m) m.Key = opName) _
|
||
.FirstOrDefault _
|
||
?.OverloadsBinaryOperator
|
||
End Function
|
||
|
||
' 因为字符串连接操作符在Linq表达式中并没有被定义,所以在这里需要特殊处理
|
||
op_Concatenates = find(stringContract)
|
||
op_Likes = find(objectLike)
|
||
op_IntegerDivisions = find(nameIntegerDivision)
|
||
|
||
For Each op As IGrouping(Of String, MethodInfo) In operators _
|
||
.Where(Function(o)
|
||
' 在这里将IsTrue/IsFalse/CType等表达式排除掉
|
||
Return OperatorExpression.opName2Linq.ContainsKey(o.Key)
|
||
End Function)
|
||
#If DEBUG Then
|
||
' Call op.Key.EchoLine
|
||
#End If
|
||
With op
|
||
If .Key = stringContract OrElse
|
||
.Key = objectLike OrElse
|
||
.Key = nameIntegerDivision Then
|
||
|
||
' 前面已经被处理过了,不需要再额外处理这个运算符了
|
||
Continue For
|
||
End If
|
||
End With
|
||
|
||
' 将运算符字符串名称转换为Linq表达式类型名称
|
||
Dim name As ExpressionType = OperatorExpression.opName2Linq(op.Key)
|
||
|
||
If op.First.GetParameters.Length > 1 Then
|
||
operatorsBinary(name) = op.OverloadsBinaryOperator
|
||
Else
|
||
operatorsUnary(name) = op.First
|
||
End If
|
||
Next
|
||
|
||
Me.methods = methods _
|
||
.Where(Function(m) Not m.IsStatic) _
|
||
.GroupBy(Function(func) func.Name) _
|
||
.Select(Function([overloads]) New OverloadsFunction([overloads].Key, [overloads])) _
|
||
.ToDictionary(Function(g) g.Name)
|
||
End Sub
|
||
|
||
''' <summary>
|
||
''' Returns property names and function names
|
||
''' </summary>
|
||
''' <returns></returns>
|
||
Public Function GetDynamicMemberNames() As IEnumerable(Of String)
|
||
Return PropertyNames.Objects.AsList + methods.Keys
|
||
End Function
|
||
|
||
#Region "Property Get/Set"
|
||
|
||
''' <summary>
|
||
''' Property Get
|
||
''' </summary>
|
||
''' <param name="binder"></param>
|
||
''' <returns></returns>
|
||
Public Function TryGetMember(binder As GetMemberBinder) As PropertyInfo
|
||
If PropertyNames.IndexOf(binder.Name) = -1 Then
|
||
Return Nothing
|
||
Else
|
||
Return propertyList(binder.Name)
|
||
End If
|
||
End Function
|
||
|
||
Public Function TryGetMember(ByRef name$, caseSensitive As Boolean) As PropertyInfo
|
||
If PropertyNames.IndexOf(name) = -1 Then
|
||
If Not caseSensitive Then
|
||
name = PropertyNames _
|
||
.Objects _
|
||
.Where(AddressOf name.TextEquals) _
|
||
.FirstOrDefault
|
||
|
||
If name.StringEmpty Then
|
||
Return Nothing
|
||
Else
|
||
Return propertyList(name)
|
||
End If
|
||
Else
|
||
Return Nothing
|
||
End If
|
||
Else
|
||
Return propertyList(name)
|
||
End If
|
||
End Function
|
||
|
||
''' <summary>
|
||
''' Property Set
|
||
''' </summary>
|
||
''' <param name="binder"></param>
|
||
''' <returns></returns>
|
||
Public Function TrySetMember(binder As SetMemberBinder) As PropertyInfo
|
||
If PropertyNames.IndexOf(binder.Name) = -1 Then
|
||
Return Nothing
|
||
Else
|
||
Return propertyList(binder.Name)
|
||
End If
|
||
End Function
|
||
#End Region
|
||
|
||
''' <summary>
|
||
''' Function invoke
|
||
''' </summary>
|
||
''' <param name="binder"></param>
|
||
''' <param name="args"></param>
|
||
''' <returns></returns>
|
||
Public Function TryInvokeMember(binder As InvokeMemberBinder, args() As Object) As MethodInfo
|
||
If Not methods.ContainsKey(binder.Name) Then
|
||
Return Nothing
|
||
End If
|
||
|
||
Dim [overloads] = methods(binder.Name)
|
||
Dim method As MethodInfo = [overloads].Match(args.Select(Function(o) o.GetType).ToArray)
|
||
Return method
|
||
End Function
|
||
|
||
Public Function TryUnaryOperation(binder As UnaryOperationBinder) As MethodInfo
|
||
If Not operatorsUnary.ContainsKey(binder.Operation) Then
|
||
Return Nothing
|
||
Else
|
||
Dim method = operatorsUnary(binder.Operation)
|
||
Return method
|
||
End If
|
||
End Function
|
||
|
||
Public Overrides Function ToString() As String
|
||
Return Type.ToString
|
||
End Function
|
||
|
||
#Region "Operator:Binary"
|
||
|
||
''' <summary>
|
||
''' Fix for & operator not defined!
|
||
''' </summary>
|
||
''' <returns></returns>
|
||
Public Function [Concatenate](type As Type, ByRef vector As Boolean) As MethodInfo
|
||
If op_Concatenates Is Nothing Then
|
||
Return Nothing
|
||
Else
|
||
Return binaryOperatorSelfLeft(op_Concatenates, type, vector)
|
||
End If
|
||
End Function
|
||
|
||
Private Shared Function binaryOperatorSelfLeft(op As BinaryOperator, type As Type, ByRef vector As Boolean) As MethodInfo
|
||
Dim method As MethodInfo = op.MatchRight(type)
|
||
|
||
If Not method Is Nothing Then
|
||
Return method
|
||
End If
|
||
|
||
If type.ImplementInterface(GetType(IEnumerable)) Then
|
||
vector = True
|
||
type = type.GetInterfaces _
|
||
.Where(Function(i) i.Name = NameOf(IEnumerable)) _
|
||
.First _
|
||
.GenericTypeArguments _
|
||
.First
|
||
|
||
Return op.MatchRight(type)
|
||
Else
|
||
Return Nothing
|
||
End If
|
||
End Function
|
||
|
||
''' <summary>
|
||
''' Fix for Like operator not defined in Linq.
|
||
''' </summary>
|
||
''' <returns></returns>
|
||
Public Function [Like](type As Type, ByRef vector As Boolean) As MethodInfo
|
||
If op_Likes Is Nothing Then
|
||
Return Nothing
|
||
Else
|
||
Return binaryOperatorSelfLeft(op_Likes, type, vector)
|
||
End If
|
||
End Function
|
||
|
||
Public Function [IntegerDivision](type As Type, ByRef vector As Boolean) As MethodInfo
|
||
If op_IntegerDivisions Is Nothing Then
|
||
Return Nothing
|
||
Else
|
||
Return binaryOperatorSelfLeft(op_IntegerDivisions, type, vector)
|
||
End If
|
||
End Function
|
||
|
||
Const left% = 0
|
||
Const right% = 1
|
||
|
||
Public Function TryBinaryOperation(binder As BinaryOperationBinder, type As Type, ByRef vector As Boolean) As MethodInfo
|
||
If Not operatorsBinary.ContainsKey(binder.Operation) Then
|
||
Return Nothing
|
||
End If
|
||
|
||
Dim op As BinaryOperator = operatorsBinary(binder.Operation)
|
||
Dim target As MethodInfo = Nothing
|
||
|
||
With op.MatchRight(type)
|
||
If Not .IsNothing AndAlso .GetParameters(left).ParameterType Is Me.Type Then
|
||
Return .ByRef
|
||
End If
|
||
End With
|
||
|
||
' target还是空值的话,则尝试将目标参数转换为集合类型
|
||
If Not type.ImplementInterface(GetType(IEnumerable)) Then
|
||
Return Nothing
|
||
Else
|
||
type = type.GetInterfaces _
|
||
.Where(Function(i) i.Name = NameOf(IEnumerable)) _
|
||
.First _
|
||
.GenericTypeArguments _
|
||
.First
|
||
End If
|
||
|
||
With op.MatchRight(type)
|
||
If Not .IsNothing AndAlso .GetParameters(left).ParameterType Is Me.Type Then
|
||
vector = True
|
||
Return .ByRef
|
||
End If
|
||
End With
|
||
|
||
Return Nothing
|
||
End Function
|
||
#End Region
|
||
End Class
|
||
End Namespace
|