1 #Region "Microsoft.VisualBasic::a94e940d251c96dc1bdeab9171871900, Microsoft.VisualBasic.Core\Language\Linq\Vectorization\SchemaProvider.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Class VectorSchemaProvider
35     
36     '         Properties: PropertyNames, Type
37     
38     '         Constructor: (+1 OverloadsSub New
39     '         Function: [Concatenate], [IntegerDivision], [Like], binaryOperatorSelfLeft, GetDynamicMemberNames
40     '                   ToString, TryBinaryOperation, (+2 OverloadsTryGetMember, TryInvokeMember, TrySetMember
41     '                   TryUnaryOperation
42     
43     
44     ' /********************************************************************************/
45
46 #End Region
47
48 Imports System.Dynamic
49 Imports System.Linq.Expressions
50 Imports System.Reflection
51 Imports Microsoft.VisualBasic.ComponentModel.Collection
52 Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
53 Imports Microsoft.VisualBasic.Emit.Delegates
54 Imports Microsoft.VisualBasic.Linq
55 Imports Microsoft.VisualBasic.Scripting.Runtime
56 Imports Microsoft.VisualBasic.Scripting.TokenIcer
57
58 Namespace Language.Vectorization
59
60     ''' <summary>
61     ''' Schema provider of the <see cref="VectorShadows(Of T)"/>
62     ''' </summary>
63     Public Class VectorSchemaProvider
64
65         ''' <summary>
66         ''' 单目运算符无重名的问题
67         ''' </summary>
68         ReadOnly operatorsUnary As New Dictionary(Of ExpressionType, MethodInfo)
69         ''' <summary>
70         ''' 双目运算符重载会带来重名运算符的问题
71         ''' </summary>
72         ReadOnly operatorsBinary As New Dictionary(Of ExpressionType, BinaryOperator)
73
74 #Region "VisualBasic exclusive language features"
75         ReadOnly op_Concatenates As BinaryOperator
76         ReadOnly op_Likes As BinaryOperator
77         ReadOnly op_IntegerDivisions As BinaryOperator
78 #End Region
79
80         ''' <summary>
81         ''' The overloads function
82         ''' </summary>
83         ReadOnly methods As New Dictionary(Of StringOverloadsFunction)
84         ReadOnly propertyList As Dictionary(Of StringPropertyInfo)
85
86         Public ReadOnly Property PropertyNames As Index(Of String)
87         Public ReadOnly Property Type As Type
88
89         Public Const stringContract$ = "op_Concatenate"
90         Public Const objectLike$ = "op_Like"
91         Public Const nameIntegerDivision$ = "op_IntegerDivision"
92
93         Sub New(type As Type)
94             Me.Type = type
95             Me.propertyList = type.Schema(PropertyAccess.NotSure, PublicProperty, True)
96             Me.PropertyNames = propertyList _
97                 .Values _
98                 .Select(Function([property]) [property].Name) _
99                 .Indexing
100
101             Dim methods = type.GetMethods()
102             Dim operators = methods _
103                 .Where(Function(x) InStr(x.Name, "op_") = 1 AndAlso x.IsStatic) _
104                 .GroupBy(Function(op) op.Name) _
105                 .ToArray
106
107             Dim find = Function(opName$)
108                            Return operators _
109                                .Where(Function(m) m.Key = opName) _
110                                .FirstOrDefault _
111                               ?.OverloadsBinaryOperator
112                        End Function
113
114             ' 因为字符串连接操作符在Linq表达式中并没有被定义,所以在这里需要特殊处理
115             op_Concatenates = find(stringContract)
116             op_Likes = find(objectLike)
117             op_IntegerDivisions = find(nameIntegerDivision)
118
119             For Each op As IGrouping(Of StringMethodInfo) In operators _
120                 .Where(Function(o)
121                            ' 在这里将IsTrue/IsFalse/CType等表达式排除掉
122                            Return OperatorExpression.opName2Linq.ContainsKey(o.Key)
123                        End Function)
124 #If DEBUG Then
125                 Call op.Key.EchoLine
126 #End If
127                 With op
128                     If .Key = stringContract OrElse
129                         .Key = objectLike OrElse
130                         .Key = nameIntegerDivision Then
131
132                         ' 前面已经被处理过了,不需要再额外处理这个运算符了
133                         Continue For
134                     End If
135                 End With
136
137                 ' 将运算符字符串名称转换为Linq表达式类型名称
138                 Dim name As ExpressionType = OperatorExpression.opName2Linq(op.Key)
139
140                 If op.First.GetParameters.Length > 1 Then
141                     operatorsBinary(name) = op.OverloadsBinaryOperator
142                 Else
143                     operatorsUnary(name) = op.First
144                 End If
145             Next
146
147             Me.methods = methods _
148                 .Where(Function(m) Not m.IsStatic) _
149                 .GroupBy(Function(func) func.Name) _
150                 .Select(Function([overloads]) New OverloadsFunction([overloads].Key, [overloads])) _
151                 .ToDictionary(Function(g) g.Name)
152         End Sub
153
154         ''' <summary>
155         ''' Returns property names and function names
156         ''' </summary>
157         ''' <returns></returns>
158         Public Function GetDynamicMemberNames() As IEnumerable(Of String)
159             Return PropertyNames.Objects.AsList + methods.Keys
160         End Function
161
162 #Region "Property Get/Set"
163
164         ''' <summary>
165         ''' Property Get
166         ''' </summary>
167         ''' <param name="binder"></param>
168         ''' <returns></returns>
169         Public Function TryGetMember(binder As GetMemberBinder) As PropertyInfo
170             If PropertyNames.IndexOf(binder.Name) = -1 Then
171                 Return Nothing
172             Else
173                 Return propertyList(binder.Name)
174             End If
175         End Function
176
177         Public Function TryGetMember(ByRef name$, caseSensitive As BooleanAs PropertyInfo
178             If PropertyNames.IndexOf(name) = -1 Then
179                 If Not caseSensitive Then
180                     name = PropertyNames _
181                         .Objects _
182                         .Where(AddressOf name.TextEquals) _
183                         .FirstOrDefault
184
185                     If name.StringEmpty Then
186                         Return Nothing
187                     Else
188                         Return propertyList(name)
189                     End If
190                 Else
191                     Return Nothing
192                 End If
193             Else
194                 Return propertyList(name)
195             End If
196         End Function
197
198         ''' <summary>
199         ''' Property Set
200         ''' </summary>
201         ''' <param name="binder"></param>
202         ''' <returns></returns>
203         Public Function TrySetMember(binder As SetMemberBinder) As PropertyInfo
204             If PropertyNames.IndexOf(binder.Name) = -1 Then
205                 Return Nothing
206             Else
207                 Return propertyList(binder.Name)
208             End If
209         End Function
210 #End Region
211
212         ''' <summary>
213         ''' Function invoke
214         ''' </summary>
215         ''' <param name="binder"></param>
216         ''' <param name="args"></param>
217         ''' <returns></returns>
218         Public Function TryInvokeMember(binder As InvokeMemberBinder, args() As ObjectAs MethodInfo
219             If Not methods.ContainsKey(binder.Name) Then
220                 Return Nothing
221             End If
222
223             Dim [overloads] = methods(binder.Name)
224             Dim method As MethodInfo = [overloads].Match(args.Select(Function(o) o.GetType).ToArray)
225             Return method
226         End Function
227
228         Public Function TryUnaryOperation(binder As UnaryOperationBinder) As MethodInfo
229             If Not operatorsUnary.ContainsKey(binder.Operation) Then
230                 Return Nothing
231             Else
232                 Dim method = operatorsUnary(binder.Operation)
233                 Return method
234             End If
235         End Function
236
237         Public Overrides Function ToString() As String
238             Return Type.ToString
239         End Function
240
241 #Region "Operator:Binary"
242
243         ''' <summary>
244         ''' Fix for &amp; operator not defined!
245         ''' </summary>
246         ''' <returns></returns>
247         Public Function [Concatenate](type As Type, ByRef vector As BooleanAs MethodInfo
248             If op_Concatenates Is Nothing Then
249                 Return Nothing
250             Else
251                 Return binaryOperatorSelfLeft(op_Concatenates, type, vector)
252             End If
253         End Function
254
255         Private Shared Function binaryOperatorSelfLeft(op As BinaryOperator, type As Type, ByRef vector As BooleanAs MethodInfo
256             Dim method As MethodInfo = op.MatchRight(type)
257
258             If Not method Is Nothing Then
259                 Return method
260             End If
261
262             If type.ImplementInterface(GetType(IEnumerable)) Then
263                 vector = True
264                 type = type.GetInterfaces _
265                     .Where(Function(i) i.Name = NameOf(IEnumerable)) _
266                     .First _
267                     .GenericTypeArguments _
268                     .First
269
270                 Return op.MatchRight(type)
271             Else
272                 Return Nothing
273             End If
274         End Function
275
276         ''' <summary>
277         ''' Fix for Like operator not defined in Linq.
278         ''' </summary>
279         ''' <returns></returns>
280         Public Function [Like](type As Type, ByRef vector As BooleanAs MethodInfo
281             If op_Likes Is Nothing Then
282                 Return Nothing
283             Else
284                 Return binaryOperatorSelfLeft(op_Likes, type, vector)
285             End If
286         End Function
287
288         Public Function [IntegerDivision](type As Type, ByRef vector As BooleanAs MethodInfo
289             If op_IntegerDivisions Is Nothing Then
290                 Return Nothing
291             Else
292                 Return binaryOperatorSelfLeft(op_IntegerDivisions, type, vector)
293             End If
294         End Function
295
296         Const left% = 0
297         Const right% = 1
298
299         Public Function TryBinaryOperation(binder As BinaryOperationBinder, type As Type, ByRef vector As BooleanAs MethodInfo
300             If Not operatorsBinary.ContainsKey(binder.Operation) Then
301                 Return Nothing
302             End If
303
304             Dim op As BinaryOperator = operatorsBinary(binder.Operation)
305             Dim target As MethodInfo = Nothing
306
307             With op.MatchRight(type)
308                 If Not .IsNothing AndAlso .GetParameters(left).ParameterType Is Me.Type Then
309                     Return .ByRef
310                 End If
311             End With
312
313             ' target还是空值的话,则尝试将目标参数转换为集合类型
314             If Not type.ImplementInterface(GetType(IEnumerable)) Then
315                 Return Nothing
316             Else
317                 type = type.GetInterfaces _
318                     .Where(Function(i) i.Name = NameOf(IEnumerable)) _
319                     .First _
320                     .GenericTypeArguments _
321                     .First
322             End If
323
324             With op.MatchRight(type)
325                 If Not .IsNothing AndAlso .GetParameters(left).ParameterType Is Me.Type Then
326                     vector = True
327                     Return .ByRef
328                 End If
329             End With
330
331             Return Nothing
332         End Function
333 #End Region
334     End Class
335 End Namespace