You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Darwinism/LINQ/LINQ/Framewok/DynamicCode/vbc/DynamicCompiler.vb

155 lines
7.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

Imports System.Text
Imports System.CodeDom.Compiler
Imports System.CodeDom
Imports Microsoft.VisualBasic.Linq.Statements
Imports Microsoft.VisualBasic.CodeDOM_VBC
Imports Microsoft.VisualBasic.Linq.Framework.Provider
Imports Microsoft.VisualBasic.Linq.Framework.Provider.ImportsAPI
Imports System.Reflection
Namespace Framework.DynamicCode.VBC
''' <summary>
''' 编译整个LINQ语句的动态代码编译器
''' </summary>
''' <remarks></remarks>
Public Class DynamicCompiler : Implements IDisposable
Public ReadOnly Property EntityProvider As TypeRegistry
Public ReadOnly Property ApiProvider As APIProvider
Sub New(entity As TypeRegistry, api As APIProvider)
ApiProvider = api
EntityProvider = entity
End Sub
Sub New()
Call Me.New(TypeRegistry.LoadDefault, APIProvider.LoadDefault)
End Sub
Public ReadOnly Property ImportsNamespace As List(Of String) = New List(Of String)
Public ReadOnly Property ReferenceList As New List(Of String)
Public Sub [Imports](ns As String)
Dim types As Type() = ApiProvider.GetType(ns)
For Each nsDef As Type In types
Dim name As String = nsDef.FullName
If Not ImportsNamespace.Contains(name) Then
Call ImportsNamespace.Add(name)
End If
Dim assm As String = nsDef.Assembly.Location
If Not ReferenceList.Contains(assm) Then
Call ReferenceList.Add(assm)
End If
Next
End Sub
Public Function Compile([declare] As CodeTypeDeclaration) As Type
Dim assmUnit As CodeCompileUnit = DeclareAssembly()
Dim ns As CodeNamespace = assmUnit.Namespaces.Item(0)
Call ns.Types.Add([declare])
Call ns.Imports.AddRange(Me.ImportsNamespace.ImportsNamespace)
Dim assm As Assembly = CompileDll(assmUnit, ReferenceList, EntityProvider.SDK)
Dim types As Type() = assm.GetTypes
Dim name As String = [declare].Name
Dim LQuery = (From x As Type In types
Where String.Equals(x.Name, name)
Select x).FirstOrDefault
Return LQuery
End Function
Public Shared Function DeclareAssembly() As CodeCompileUnit
Dim Assembly As CodeDom.CodeCompileUnit = New CodeDom.CodeCompileUnit
Dim DynamicCodeNameSpace As CodeDom.CodeNamespace = New CodeDom.CodeNamespace("LINQDynamicCodeCompiled")
Assembly.Namespaces.Add(DynamicCodeNameSpace)
Return Assembly
End Function
Private Function DeclareType() As CodeDom.CodeTypeDeclaration
Dim [Module] = DynamicCode.VBC.TokenCompiler.DeclareType(ModuleName, LINQStatement.var, LINQStatement.PreDeclare)
Call [Module].Members.Add(New DynamicCode.VBC.WhereConditionTestCompiler(LINQStatement).Compile)
Call [Module].Members.Add(DeclareSetObject)
Call [Module].Members.Add(New DynamicCode.VBC.SelectConstructCompiler(LINQStatement).Compile)
Return [Module]
End Function
Private Function DeclareSetObject() As CodeDom.CodeMemberMethod
Dim StatementCollection As CodeDom.CodeStatementCollection = New CodeDom.CodeStatementCollection
Call StatementCollection.Add(New CodeDom.CodeAssignStatement(New CodeDom.CodeFieldReferenceExpression(New CodeDom.CodeThisReferenceExpression(), LINQStatement.var.Name), New CodeDom.CodeArgumentReferenceExpression("p")))
For Each ReadOnlyObject In LINQStatement.PreDeclare
Call StatementCollection.Add(New DynamicCode.VBC.ReadOnlyObjectCompiler(ReadOnlyObject).Compile)
Next
Dim SetObject As CodeDom.CodeMemberMethod = DeclareFunction(SetObjectName, "System.Boolean", StatementCollection)
SetObject.Parameters.Add(New CodeDom.CodeParameterDeclarationExpression(LINQStatement.var.TypeId, "p"))
SetObject.Attributes = CodeDom.MemberAttributes.Public
Return SetObject
End Function
Public Function Compile(ReferenceAssemblys As String()) As System.Reflection.Assembly
Dim Code = DeclareAssembly()
Dim Assembly = CodeDOMExtension.Compile(Code, ReferenceAssemblys, DotNETReferenceAssembliesDir)
Return Assembly
End Function
''' <summary>
''' Declare a function with a specific function name and return type. please notice that in this newly
''' declare function there is always a local variable name rval using for return the value.
''' (申明一个方法,返回指定类型的数据并且具有一个特定的函数名,请注意,在这个新申明的函数之中,
''' 固定含有一个rval的局部变量用于返回数据)
''' </summary>
''' <param name="Name">Function name.(函数名)</param>
''' <param name="Type">Function return value type.(该函数的返回值类型)</param>
''' <returns>A codeDOM object model of the target function.(一个函数的CodeDom对象模型)</returns>
''' <remarks></remarks>
Public Shared Function DeclareFunction(Name As String, Type As String, Statements As CodeDom.CodeStatementCollection) As CodeDom.CodeMemberMethod
Dim CodeMemberMethod As CodeDom.CodeMemberMethod = New CodeDom.CodeMemberMethod()
CodeMemberMethod.Name = Name : CodeMemberMethod.ReturnType = New CodeDom.CodeTypeReference(Type) '创建一个名为“WhereTest”返回值类型为Boolean的无参数的函数
If String.Equals(Type, "System.Boolean", StringComparison.OrdinalIgnoreCase) Then
CodeMemberMethod.Statements.Add(New CodeDom.CodeVariableDeclarationStatement(Type, "rval", New CodeDom.CodePrimitiveExpression(True))) '创建一个用于返回值的局部变量,对于逻辑值,默认为真
Else
CodeMemberMethod.Statements.Add(New CodeDom.CodeVariableDeclarationStatement(Type, "rval")) '创建一个用于返回值的局部变量
End If
If Not (Statements Is Nothing OrElse Statements.Count = 0) Then
CodeMemberMethod.Statements.AddRange(Statements)
End If
CodeMemberMethod.Statements.Add(New CodeDom.CodeMethodReturnStatement(New CodeDom.CodeVariableReferenceExpression("rval"))) '引用返回值的局部变量
Return CodeMemberMethod
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' 检测冗余的调用
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: 释放托管状态(托管对象)。
End If
' TODO: 释放非托管资源(非托管对象)并重写下面的 Finalize()。
' TODO: 将大型字段设置为 null。
End If
Me.disposedValue = True
End Sub
' TODO: 仅当上面的 Dispose( disposing As Boolean)具有释放非托管资源的代码时重写 Finalize()。
'Protected Overrides Sub Finalize()
' ' 不要更改此代码。 请将清理代码放入上面的 Dispose( disposing As Boolean)中。
' Dispose(False)
' MyBase.Finalize()
'End Sub
' Visual Basic 添加此代码是为了正确实现可处置模式。
Public Sub Dispose() Implements IDisposable.Dispose
' 不要更改此代码。 请将清理代码放入上面的 Dispose (disposing As Boolean)中。
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
End Namespace