1 #Region "Microsoft.VisualBasic::ca68fd3a8807462f3364f60b8e5d4144, Microsoft.VisualBasic.Core\Scripting\InputHandler.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 '     Module InputHandler
35
36 '         Properties: [String], CasterString, Types
37
38 '         Function: [DirectCast], (+2 Overloads) [GetType], (+2 Overloads) CastArray, Convertible, (+2 OverloadsCTypeDynamic
39 '                   DefaultTextParser, IsPrimitive, StringParser, ToString
40
41 '         Sub: CapabilityPromise
42
43
44 ' /********************************************************************************/
45
46 #End Region
47
48 Imports System.Array
49 Imports System.Drawing
50 Imports System.IO
51 Imports System.Reflection
52 Imports System.Runtime.CompilerServices
53 Imports System.Text
54 Imports System.Text.RegularExpressions
55 Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Logging
56 Imports Microsoft.VisualBasic.ComponentModel.Collection
57 Imports Microsoft.VisualBasic.ComponentModel.Ranges.Model
58 Imports Microsoft.VisualBasic.Imaging
59 Imports Microsoft.VisualBasic.Language
60 Imports Microsoft.VisualBasic.Language.Default
61 Imports Microsoft.VisualBasic.Scripting.Runtime
62 Imports Microsoft.VisualBasic.Serialization
63 Imports CLI = Microsoft.VisualBasic.CommandLine.CommandLine
64
65 Namespace Scripting
66
67     ''' <summary>
68     ''' Handles the input text string from commandline or scripting, dealing with the 
69     ''' conversion of this input string to .NET object in a more easy way.
70     ''' (转换从终端或者脚本文件之中输入的字符串的类型的转换)
71     ''' </summary>
72     Public Module InputHandler
73
74         ''' <summary>
75         ''' Object为字符串类型,这个字典可以讲字符串转为目标类型
76         ''' </summary>
77         ''' <remarks></remarks>
78         Public ReadOnly Property CasterString As New Dictionary(Of Type, LoadObject) From {
79  _
80             {GetType(String), Function(s$) s},
81             {GetType(Char), AddressOf Casting.CastChar},
82             {GetType(Integer), AddressOf Casting.CastInteger},
83             {GetType(Double), AddressOf Casting.ParseNumeric},
84             {GetType(Long), AddressOf Casting.CastLong},
85             {GetType(Boolean), AddressOf ParseBoolean},
86             {GetType(Char()), AddressOf Casting.CastCharArray},
87             {GetType(Date), AddressOf Casting.CastDate},
88             {GetType(StringBuilder), AddressOf Casting.CastStringBuilder},
89             {GetType(CLI), AddressOf Casting.CastCommandLine},
90             {GetType(Image), AddressOf Casting.CastImage},
91             {GetType(FileInfo), AddressOf Casting.CastFileInfo},
92             {GetType(Graphics2D), AddressOf Casting.CastGDIPlusDeviceHandle},
93             {GetType(Color), AddressOf TranslateColor},
94             {GetType(Font), AddressOf Casting.CastFont},
95             {GetType(System.Net.IPEndPoint), AddressOf Casting.CastIPEndPoint},
96             {GetType(LogFile), AddressOf Casting.CastLogFile},
97             {GetType(Process), AddressOf Casting.CastProcess},
98             {GetType(RegexOptions), AddressOf Casting.CastRegexOptions},
99             {GetType(Single), AddressOf Casting.CastSingle},
100             {GetType(Decimal), Function(x) CDec(x)},
101             {GetType(Point), AddressOf PointParser},
102             {GetType(PointF), AddressOf FloatPointParser},
103             {GetType(Size), AddressOf SizeParser},
104             {GetType(SizeF), AddressOf FloatSizeParser},
105             {GetType(DoubleRange), AddressOf NumericRangeParser}
106         }
107
108         <MethodImpl(MethodImplOptions.AggressiveInlining)>
109         Public Function StringParser(type As Type) As DefaultValue(Of Func(Of StringObject))
110             Return New Func(Of StringObject)(Function(s$) s.CTypeDynamic(type))
111         End Function
112
113         ''' <summary>
114         ''' Converts a string expression which was input from the console or script file to the specified type.
115         ''' (请注意,函数只是转换最基本的数据类型,转换错误会返回空值,空字符串也会返回空值)
116         ''' </summary>
117         ''' <param name="expression">The string expression to convert.</param>
118         ''' <param name="target">The type to which to convert the object.</param>
119         ''' <returns>An object whose type at run time is the requested target type.</returns>
120         <Extension> Public Function CTypeDynamic(expression$, target As Type) As Object
121             If expression.StringEmpty Then
122                 Return Nothing
123             End If
124             If _CasterString.ContainsKey(target) Then
125                 Dim caster As LoadObject = _CasterString(target)
126                 Return caster(expression$)
127             End If
128
129             Static errCaster As New Index(Of String)
130
131             If expression.Length < 100 Then
132                 ' 过长的字符串在内存之中累积下来可能会导致内存溢出
133                 ' 在这里对表达式做下长度限制
134                 If errCaster.IndexOf(expression & "|" & target.FullName) > -1 Then
135                     ' This is a exists error
136                     Return Nothing
137                 End If
138             End If
139
140             Try
141                 Return Conversion.CTypeDynamic(expression, target)
142             Catch ex As Exception
143
144                 If expression.Length < 100 Then
145                     errCaster.Add(expression & "|" & target.FullName)
146                 End If
147
148                 ex = New Exception($"{expression} ==> {target.FullName}", ex)
149                 Call App.LogException(ex, MethodBase.GetCurrentMethod.GetFullName)
150                 Return Nothing
151             End Try
152         End Function
153
154         ''' <summary>
155         ''' Converts a string expression which was input from the console or script file to the specified type.
156         ''' (请注意,函数只是转换最基本的数据类型,转换错误会返回空值)
157         ''' </summary>
158         ''' <param name="expr">The string expression to convert.</param>
159         ''' <typeparam name="T">The type to which to convert the object.</typeparam>
160         ''' <returns>An object whose type at run time is the requested target type.</returns>
161         <Extension> Public Function CTypeDynamic(Of T)(expr$, Optional [default] As T = NothingAs T
162             Dim value As Object = CTypeDynamic(expr, GetType(T))
163
164             If value Is Nothing Then
165                 Return [default]
166             Else
167                 Return DirectCast(value, T)
168             End If
169         End Function
170
171         ''' <summary>
172         ''' 默认的字符串解析方法为<see cref="CTypeDynamic"/>脚本值动态转换函数
173         ''' </summary>
174         ''' <typeparam name="T"></typeparam>
175         ''' <returns></returns>
176         <MethodImpl(MethodImplOptions.AggressiveInlining)>
177         Public Function DefaultTextParser(Of T)() As DefaultValue(Of IStringParser(Of T))
178             Return New IStringParser(Of T)(AddressOf CTypeDynamic(Of T)).AsDefault
179         End Function
180
181         ''' <summary>
182         ''' Does this type can be cast from the <see cref="String"/> type?(目标类型能否由字符串转换过来??)
183         ''' </summary>
184         ''' <param name="targetType"></param>
185         ''' <returns></returns>
186         ''' 
187         <MethodImpl(MethodImplOptions.AggressiveInlining)>
188         Public Function IsPrimitive(targetType As Type) As Boolean
189             Return CasterString.ContainsKey(targetType)
190         End Function
191
192         ''' <summary>
193         ''' Dynamics updates the capability of function <see cref="InputHandler.CTypeDynamic(String, Type)"/>, 
194         ''' <see cref="InputHandler.CTypeDynamic(Of T)(String, T)"/> and 
195         ''' <see cref="InputHandler.IsPrimitive(Type)"/>
196         ''' </summary>
197         ''' <param name="briefName"></param>
198         ''' <param name="stringConvertType"></param>
199         ''' <param name="cast"></param>
200         Public Sub CapabilityPromise(briefName$, stringConvertType As Type, cast As LoadObject)
201             With _CasterString
202                 If .ContainsKey(stringConvertType) Then
203                     Call .Remove(stringConvertType)
204                 End If
205
206                 Call .Add(stringConvertType, cast)
207             End With
208
209             Dim key$ = briefName.ToLower
210
211             If Types.ContainsKey(key) Then
212                 Call Types.Remove(key)
213             End If
214             Call Types.Add(key, stringConvertType)
215         End Sub
216
217         ''' <summary>
218         ''' Enumerate all of the types that can be handled in this module. All of the key string is in lower case.(键值都是小写的)
219         ''' </summary>
220         Public ReadOnly Property Types As New SortedDictionary(Of String, Type) From {
221  _
222                 {"string"GetType(String)},
223                 {"integer"GetType(Integer)},
224                 {"int32"GetType(Integer)},
225                 {"int64"GetType(Long)},
226                 {"long"GetType(Long)},
227                 {"double"GetType(Double)},
228                 {"byte"GetType(Byte)},
229                 {"date"GetType(Date)},
230                 {"logfile"GetType(LogFile)},
231                 {"color"GetType(Color)},
232                 {"process"GetType(Process)},
233                 {"font"GetType(Font)},
234                 {"image"GetType(Image)},
235                 {"fileinfo"GetType(IO.FileInfo)},
236                 {"ipaddress"GetType(System.Net.IPAddress)},
237                 {"commandline"GetType(CLI)},
238                 {"gdi+"GetType(Graphics2D)},
239                 {"stringbuilder"GetType(StringBuilder)},
240                 {"boolean"GetType(Boolean)},
241                 {"char()"GetType(Char())},
242                 {"string()"GetType(String())},
243                 {"integer()"GetType(Integer())},
244                 {"double()"GetType(Double())},
245                 {"bitmap"GetType(Bitmap)},
246                 {"object"GetType(Object)},
247                 {"regexoptions"GetType(RegexOptions)}
248         }
249
250         ''' <summary>
251         ''' Get .NET <see cref="Type"/> definition info from its name.
252         ''' (类型获取失败会返回空值,大小写不敏感)
253         ''' </summary>
254         ''' <param name="name">Case insensitive.(类型的名称简写)</param>
255         ''' <param name="ObjectGeneric">是否出错的时候返回<see cref="Object"/>类型,默认返回Nothing</param>
256         ''' <returns></returns>
257         Public Function [GetType](name As Value(Of String), Optional ObjectGeneric As Boolean = FalseAs Type
258             If Types.ContainsKey(name = name.Value.ToLower) Then
259                 Return Types(name)
260             Else
261                 Dim typeInfo As Type = Type.GetType(name, FalseTrue)
262
263                 If typeInfo Is Nothing AndAlso ObjectGeneric Then
264                     Return GetType(Object)
265                 Else
266                     Return typeInfo
267                 End If
268             End If
269         End Function
270
271         Public Function [GetType](obj As ObjectOptional ObjectGeneric As Boolean = FalseAs Type
272             If obj Is Nothing Then
273                 If ObjectGeneric Then
274                     Return GetType(Object)
275                 Else
276                     Return Nothing
277                 End If
278             Else
279                 Return obj.GetType
280             End If
281         End Function
282
283         ''' <summary>
284         ''' <see cref="System.Type"/> information for <see cref="System.String"/> type from GetType operator
285         ''' </summary>
286         ''' <returns></returns>
287         Public ReadOnly Property [String] As Type = GetType(String)
288
289         ''' <summary>
290         ''' Does the <paramref name="inputtype"/> type can be cast to type <paramref name="DefType"/>.
291         ''' (主要为了方便减少脚本编程模块的代码)
292         ''' </summary>
293         ''' <param name="inputType"></param>
294         ''' <param name="DefType"></param>
295         ''' <returns></returns>
296         ''' 
297         <MethodImpl(MethodImplOptions.AggressiveInlining)>
298         Public Function Convertible(inputType As Type, DefType As Type) As Boolean
299             Return inputType.Equals([String]) AndAlso CasterString.ContainsKey(DefType)
300         End Function
301
302         ''' <summary>
303         ''' <seealso cref="CStrSafe"/>, 出现错误的时候总是会返回空字符串的
304         ''' </summary>
305         ''' <param name="obj"></param>
306         ''' <returns></returns>
307         ''' 
308         <MethodImpl(MethodImplOptions.AggressiveInlining)>
309         Public Function ToString(obj As ObjectOptional null$ = ""As String
310             Return CStrSafe(obj, null)
311         End Function
312
313         ''' <summary>
314         ''' The parameter <paramref name="obj"/> should implements a <see cref="IEnumerable"/> interface on the type. and then DirectCast object to target type.
315         ''' </summary>
316         ''' <typeparam name="T"></typeparam>
317         ''' <param name="obj"></param>
318         ''' <returns></returns>
319         Public Function CastArray(Of T)(obj As ObjectAs T()
320             Dim array = DirectCast(obj, IEnumerable)
321             Dim data = (From val In array Select DirectCast(val, T)).ToArray
322             Return data
323         End Function
324
325         Public Function CastArray(obj As Object, type As Type) As Object
326             If Array.IndexOf(obj.GetType.GetInterfaces, GetType(IEnumerable)) = -1 Then
327                 Return obj
328             End If
329
330             Dim source As IEnumerable = DirectCast(obj, IEnumerable)
331             Dim data = LinqAPI.Exec(Of Object) _
332  _
333                 () <= From val As Object
334                       In source
335                       Let value = Conversion.CTypeDynamic(val, type)
336                       Select value
337
338             Return [DirectCast](data, type)
339         End Function
340
341         ''' <summary>
342         ''' Cast the <see cref="Object"/> array to typed object array.
343         ''' </summary>
344         ''' <param name="array"></param>
345         ''' <param name="type">数组里面的元素的类型</param>
346         ''' <returns></returns>
347         Public Function [DirectCast](array As Object(), type As Type) As Object
348             Dim out = CreateInstance(type, array.Length)
349             Call Copy(array, out, array.Length) ' 直接复制不能够正常工作
350             Return out
351         End Function
352     End Module
353 End Namespace