From a39f9b35e0a694fa3ea68d46d7cb33fc35ff2f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AC=9D=E6=A1=82=E7=B6=B1?= Date: Fri, 5 Feb 2016 16:37:39 +0800 Subject: [PATCH] reconstruct of the namespace --- LINQ/LINQ/APP/Program.vb | 3 +- .../DynamicCode/vbc/DynamicCompiler.vb | 8 +- .../DynamicCode/vbc/ReadOnlyObjectCompiler.vb | 4 +- .../vbc/SelectConstructCompiler.vb | 2 +- .../vbc/WhereConditionTestCompiler.vb | 6 +- LINQ/LINQ/Framewok/LQueryFramework.vb | 2 +- LINQ/LINQ/Framewok/ObjectModel/LINQ.vb | 12 +- LINQ/LINQ/LDM/Expression/Closure.vb | 43 +++++++ LINQ/LINQ/LDM/Expression/Expression.vb | 6 + LINQ/LINQ/LDM/Expression/FromClosure.vb | 60 ++++++++++ LINQ/LINQ/LDM/Expression/InClosure.vb | 81 +++++++++++++ LINQ/LINQ/LDM/Expression/LetClosure.vb | 47 ++++++++ LINQ/LINQ/LDM/Expression/SelectClosure.vb | 33 ++++++ LINQ/LINQ/LDM/Expression/WhereClosure.vb | 31 +++++ .../Parser/ClosureParser.vb | 0 .../Parser/ClosureTokens.vb | 0 .../Parser}/LINQStatement.vb | 108 +++++++++--------- .../Parser}/Tokens/Closure.vb | 18 +-- .../Parser}/Tokens/FromClosure.vb | 27 ++--- .../Parser}/Tokens/InClosure.vb | 22 +--- LINQ/LINQ/LDM/Parser/Tokens/LetClosure.vb | 47 ++++++++ .../Parser}/Tokens/Options.vb | 0 .../Parser}/Tokens/SelectClosure.vb | 21 ++-- .../Parser}/Tokens/WhereClosure.vb | 13 +-- LINQ/LINQ/LINQ.vbproj | 27 +++-- LINQ/LINQ/Statement/Tokens/LetClosure.vb | 100 ---------------- 26 files changed, 482 insertions(+), 239 deletions(-) create mode 100644 LINQ/LINQ/LDM/Expression/Closure.vb create mode 100644 LINQ/LINQ/LDM/Expression/Expression.vb create mode 100644 LINQ/LINQ/LDM/Expression/FromClosure.vb create mode 100644 LINQ/LINQ/LDM/Expression/InClosure.vb create mode 100644 LINQ/LINQ/LDM/Expression/LetClosure.vb create mode 100644 LINQ/LINQ/LDM/Expression/SelectClosure.vb create mode 100644 LINQ/LINQ/LDM/Expression/WhereClosure.vb rename LINQ/LINQ/{Statement => LDM}/Parser/ClosureParser.vb (100%) rename LINQ/LINQ/{Statement => LDM}/Parser/ClosureTokens.vb (100%) rename LINQ/LINQ/{Statement => LDM/Parser}/LINQStatement.vb (55%) rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/Closure.vb (77%) rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/FromClosure.vb (64%) rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/InClosure.vb (79%) create mode 100644 LINQ/LINQ/LDM/Parser/Tokens/LetClosure.vb rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/Options.vb (100%) rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/SelectClosure.vb (55%) rename LINQ/LINQ/{Statement => LDM/Parser}/Tokens/WhereClosure.vb (63%) delete mode 100644 LINQ/LINQ/Statement/Tokens/LetClosure.vb diff --git a/LINQ/LINQ/APP/Program.vb b/LINQ/LINQ/APP/Program.vb index 01e20c0..1acb5f2 100644 --- a/LINQ/LINQ/APP/Program.vb +++ b/LINQ/LINQ/APP/Program.vb @@ -7,8 +7,7 @@ Public Function Main() As Integer Dim s As String = "From var As Type In $source->parallel Let x = var -> aa(d,""g ++ "") where x -> test2(test3(xx),var) is true select new varType(var,x), x+3" - Dim rs = ClosureParser.TryParse(s) - + Dim expr = LINQ.Statements.LINQStatement.TryParse(s) Return GetType(CLI).RunCLI(App.CommandLine, AddressOf __exeEmpty) End Function diff --git a/LINQ/LINQ/Framewok/DynamicCode/vbc/DynamicCompiler.vb b/LINQ/LINQ/Framewok/DynamicCode/vbc/DynamicCompiler.vb index a19e83b..2e39763 100644 --- a/LINQ/LINQ/Framewok/DynamicCode/vbc/DynamicCompiler.vb +++ b/LINQ/LINQ/Framewok/DynamicCode/vbc/DynamicCompiler.vb @@ -56,7 +56,7 @@ Namespace Framework.DynamicCode.VBC End Function Private Function DeclareType() As CodeDom.CodeTypeDeclaration - Dim [Module] = DynamicCode.VBC.TokenCompiler.DeclareType(ModuleName, LINQStatement.Object, LINQStatement.ReadOnlyObjects) + 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) @@ -66,13 +66,13 @@ Namespace Framework.DynamicCode.VBC 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.Object.Name), New CodeDom.CodeArgumentReferenceExpression("p"))) - For Each ReadOnlyObject In LINQStatement.ReadOnlyObjects + 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.Object.TypeId, "p")) + SetObject.Parameters.Add(New CodeDom.CodeParameterDeclarationExpression(LINQStatement.var.TypeId, "p")) SetObject.Attributes = CodeDom.MemberAttributes.Public Return SetObject End Function diff --git a/LINQ/LINQ/Framewok/DynamicCode/vbc/ReadOnlyObjectCompiler.vb b/LINQ/LINQ/Framewok/DynamicCode/vbc/ReadOnlyObjectCompiler.vb index 8b69e47..f5586d6 100644 --- a/LINQ/LINQ/Framewok/DynamicCode/vbc/ReadOnlyObjectCompiler.vb +++ b/LINQ/LINQ/Framewok/DynamicCode/vbc/ReadOnlyObjectCompiler.vb @@ -11,8 +11,8 @@ End Sub Public Function Compile() As CodeDom.CodeStatement - Dim AssignStatement = New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression(Target.Name), Target.Expression) '生成赋值语句,设置函数返回值 - Return AssignStatement + 'Dim AssignStatement = New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression(Target.Name), Target.Expression) '生成赋值语句,设置函数返回值 + 'Return AssignStatement End Function Public Overrides Function ToString() As String diff --git a/LINQ/LINQ/Framewok/DynamicCode/vbc/SelectConstructCompiler.vb b/LINQ/LINQ/Framewok/DynamicCode/vbc/SelectConstructCompiler.vb index 1b171ad..a068628 100644 --- a/LINQ/LINQ/Framewok/DynamicCode/vbc/SelectConstructCompiler.vb +++ b/LINQ/LINQ/Framewok/DynamicCode/vbc/SelectConstructCompiler.vb @@ -11,7 +11,7 @@ End Sub Public Function Compile() As CodeDom.CodeMemberMethod - Dim AssignStatement = New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression("rval"), Statement.SelectConstruct.Expression) '生成赋值语句,设置函数返回值 + Dim AssignStatement = New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression("rval"), Statement.SelectClosure.Expression) '生成赋值语句,设置函数返回值 Dim [Function] As CodeDom.CodeMemberMethod = DynamicCode.VBC.DynamicCompiler.DeclareFunction( SelectMethodName, "System.Object", New CodeDom.CodeStatementCollection From {AssignStatement}) [Function].Attributes = CodeDom.MemberAttributes.Public diff --git a/LINQ/LINQ/Framewok/DynamicCode/vbc/WhereConditionTestCompiler.vb b/LINQ/LINQ/Framewok/DynamicCode/vbc/WhereConditionTestCompiler.vb index 038835a..5de38fe 100644 --- a/LINQ/LINQ/Framewok/DynamicCode/vbc/WhereConditionTestCompiler.vb +++ b/LINQ/LINQ/Framewok/DynamicCode/vbc/WhereConditionTestCompiler.vb @@ -17,9 +17,9 @@ Public Function Compile() As CodeDom.CodeTypeMember Dim StatementCollection As CodeDom.CodeStatementCollection = Nothing - If Not Statement.ConditionTest.Expression Is Nothing Then + If Not Statement.Where.Expression Is Nothing Then StatementCollection = New CodeDom.CodeStatementCollection - StatementCollection.Add(New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression("rval"), Statement.ConditionTest.Expression)) + StatementCollection.Add(New CodeDom.CodeAssignStatement(New CodeDom.CodeVariableReferenceExpression("rval"), Statement.Where.Expression)) End If Dim [Function] As CodeDom.CodeMemberMethod = DynamicCompiler.DeclareFunction(FunctionName, "System.Boolean", StatementCollection) [Function].Attributes = CodeDom.MemberAttributes.Public @@ -27,7 +27,7 @@ End Function Public Overrides Function ToString() As String - Return Statement.ConditionTest.ToString + Return Statement.Where.ToString End Function End Class End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/Framewok/LQueryFramework.vb b/LINQ/LINQ/Framewok/LQueryFramework.vb index a838922..cb390b0 100644 --- a/LINQ/LINQ/Framewok/LQueryFramework.vb +++ b/LINQ/LINQ/Framewok/LQueryFramework.vb @@ -148,7 +148,7 @@ Namespace Framework ''' ''' Friend Function CreateObjectModel(Statement As LINQStatement) As LINQ.Framework.ObjectModel.LINQ - If Statement.Collection.IsParallel Then + If Statement.source.IsParallel Then Return New ParallelLINQ(Statement:=Statement, FrameworkRuntime:=Me.Runtime) Else Return New LINQ.Framework.ObjectModel.LINQ(Statement:=Statement, Runtime:=Me.Runtime) diff --git a/LINQ/LINQ/Framewok/ObjectModel/LINQ.vb b/LINQ/LINQ/Framewok/ObjectModel/LINQ.vb index a98c767..4c6a4bc 100644 --- a/LINQ/LINQ/Framewok/ObjectModel/LINQ.vb +++ b/LINQ/LINQ/Framewok/ObjectModel/LINQ.vb @@ -19,20 +19,20 @@ Namespace Framework.ObjectModel Sub New(Statement As LINQStatement, Runtime As I_DynamicsRuntime) Me.StatementInstance = Statement.CreateInstance 'Create a instance for the LINQ entity and intialzie the components - Me.Test = Function() Statement.ConditionTest.TestMethod.Invoke(StatementInstance, Nothing) 'Construct the Lambda expression - Me.SetObject = Function(p As Object) Statement.Object.SetObject.Invoke(StatementInstance, {p}) - Me.SelectConstruct = Function() Statement.SelectConstruct.SelectMethod.Invoke(StatementInstance, Nothing) + Me.Test = Function() Statement.Where.TestMethod.Invoke(StatementInstance, Nothing) 'Construct the Lambda expression + Me.SetObject = Function(p As Object) Statement.var.SetObject.Invoke(StatementInstance, {p}) + Me.SelectConstruct = Function() Statement.SelectClosure.SelectMethod.Invoke(StatementInstance, Nothing) Me.source = LINQ.GetCollection(Statement, Runtime) Me.Statement = Statement Me.FrameworkRuntime = Runtime End Sub Protected Friend Shared Function GetCollection(Statement As LINQStatement, Runtime As I_DynamicsRuntime) As Object() - If Statement.Collection.Type = Statements.Tokens.InClosure.CollectionTypes.File Then - Return Statement.Collection.ILINQCollection.GetCollection(Statement.Collection.Value) + If Statement.source.Type = Statements.Tokens.InClosure.CollectionTypes.File Then + Return Statement.source.ILINQCollection.GetCollection(Statement.source.Value) Else '返回运行时环境中的对象集合 - Return Runtime.GetCollection(Statement.Collection) + Return Runtime.GetCollection(Statement.source) End If End Function diff --git a/LINQ/LINQ/LDM/Expression/Closure.vb b/LINQ/LINQ/LDM/Expression/Closure.vb new file mode 100644 index 0000000..ce89796 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/Closure.vb @@ -0,0 +1,43 @@ +Imports Microsoft.VisualBasic.LINQ.TokenIcer + +Namespace LDM.Expression + + Public MustInherit Class Closure + + Protected _statement As LINQStatement + Protected _source As ClosureTokens + + Sub New(type As TokenParser.Tokens, tokens As ClosureTokens(), parent As LINQStatement) + _source = GetTokens(type, from:=tokens) + _statement = parent + + If _source Is Nothing Then + If type = TokenParser.Tokens.From OrElse + type = TokenParser.Tokens.In OrElse + type = TokenParser.Tokens.Select Then + ' LET and SELECT is optional + ' But From, In and Select is required + ' If missing, then syntax error, throw exception + Dim msg As String = String.Format(MissingRequiredField, type) + Throw New SyntaxErrorException(msg) + End If + End If + End Sub + + Sub New(token As ClosureTokens, parent As LINQStatement) + _source = token + _statement = parent + End Sub + + Const MissingRequiredField As String = "Missing the required LINQ statement token {0}!" + + Public Overrides Function ToString() As String + Return _source.ToString + End Function + + Public Shared Function GetTokens(type As TokenParser.Tokens, from As ClosureTokens()) As ClosureTokens + Dim LQuery = (From x As ClosureTokens In from Where x.Token = type Select x).FirstOrDefault + Return LQuery + End Function + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/Expression.vb b/LINQ/LINQ/LDM/Expression/Expression.vb new file mode 100644 index 0000000..65f568f --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/Expression.vb @@ -0,0 +1,6 @@ +Namespace LDM.Expression + + Public Class Expression + + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/FromClosure.vb b/LINQ/LINQ/LDM/Expression/FromClosure.vb new file mode 100644 index 0000000..ebc36e4 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/FromClosure.vb @@ -0,0 +1,60 @@ +Imports Microsoft.VisualBasic.LINQ.Framework +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode.VBC +Imports Microsoft.VisualBasic.LINQ.Framework.LQueryFramework + +Namespace LDM.Expression + + ''' + ''' The init variable. + ''' + Public Class FromClosure : Inherits Closure + + ''' + ''' 变量的名称 + ''' + ''' + ''' + ''' + Public Property Name As String + ''' + ''' 变量的类型标识符 + ''' + ''' + ''' + ''' + Public Property TypeId As String + + Public Property RegistryType As RegistryItem + + Friend SetObject As System.Reflection.MethodInfo + + Sub New(tokens As ClosureTokens(), parent As LINQStatement) + Call MyBase.New(TokenIcer.TokenParser.Tokens.From, tokens, parent) + + 'Me.RegistryType = Statement.TypeRegistry.Find(TypeId) + 'If RegistryType Is Nothing Then + ' Throw New TypeMissingExzception("Could not found any information about the type {0}.", TypeId) + 'Else + ' Dim ILINQCollection As System.Type = _tokens.ObjectCollection.LoadExternalModule(RegistryType) + ' Statement.Collection.ILINQCollection = Activator.CreateInstance(ILINQCollection) + ' Me.TypeId = Statement.Collection.ILINQCollection.GetEntityType.FullName + 'End If + End Sub + + Public Overridable Function ToFieldDeclaration() As CodeDom.CodeMemberField + Dim CodeMemberField = New CodeDom.CodeMemberField(TypeId, Name) + CodeMemberField.Attributes = CodeDom.MemberAttributes.Public + + Return CodeMemberField + End Function + + Public Sub Initialize() + Me.SetObject = DynamicInvoke.GetMethod(_statement.ILINQProgram, DynamicCompiler.SetObjectName) + End Sub + + Public Overrides Function ToString() As String + Return String.Format("Dim {0} As {1}", Name, TypeId) + End Function + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/InClosure.vb b/LINQ/LINQ/LDM/Expression/InClosure.vb new file mode 100644 index 0000000..c90d353 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/InClosure.vb @@ -0,0 +1,81 @@ +Imports Microsoft.VisualBasic.LINQ.Framework + +Namespace LDM.Expression + + ''' + ''' 表示目标对象的数据集合的文件路径或者内存对象的引用 + ''' + ''' + Public Class InClosure : Inherits Closure + + Public Enum CollectionTypes + ''' + ''' 目标集合类型为一个数据文件 + ''' + ''' + File + ''' + ''' 目标集合类型为一个内存对象的引用 + ''' + ''' + Reference + End Enum + + Dim CollectionType As InClosure.CollectionTypes = CollectionTypes.File + ''' + ''' ILINQCollection对象的实例 + ''' + ''' + ''' + ''' + Public Property ILINQCollection As Framework.ILINQCollection + + Public ReadOnly Property Type As InClosure.CollectionTypes + Get + Return CollectionType + End Get + End Property + + Public ReadOnly Property IsParallel As Boolean + Get + Return False + End Get + End Property + + ''' + ''' The file io object url or a object collection reference in the LINQ Frameowrk runtime. + ''' + ''' + ''' + ''' + Public ReadOnly Property Value As String + Get + ' Return _original + End Get + End Property + + Sub New(tokens As ClosureTokens(), parent As LINQStatement) + Call MyBase.New(TokenIcer.TokenParser.Tokens.In, tokens, parent) + End Sub + + Public Overrides Function ToString() As String + 'If Type = CollectionTypes.File Then + ' Return String.Format("(File) {0}", Me._original) + 'Else + ' Return Type.ToString + 'End If + End Function + + ''' + ''' 加载外部模块之中的ILINQCollection类型信息 + ''' + ''' + ''' + ''' + Public Shared Function LoadExternalModule(RegistryItem As RegistryItem) As Type + Dim assm As System.Reflection.Assembly = + System.Reflection.Assembly.LoadFrom(RegistryItem.AssemblyFullPath) + Return assm.GetType(RegistryItem.TypeId) + End Function + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/LetClosure.vb b/LINQ/LINQ/LDM/Expression/LetClosure.vb new file mode 100644 index 0000000..2a02ed8 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/LetClosure.vb @@ -0,0 +1,47 @@ +Imports System.Text.RegularExpressions +Imports System.Text + +Namespace LDM.Expression + + ''' + ''' Object declared using a LET expression.(使用Let语句所声明的只读对象) + ''' + ''' + Public Class LetClosure : Inherits Closure + + Friend Expression As CodeDom.CodeExpression + + ''' + ''' + ''' + ''' + Sub New(token As ClosureTokens, parent As LINQStatement) + Call MyBase.New(token, parent) + 'Dim Name As String = Regex.Match([Declare], ".+?\=").Value + 'MyBase.Name = Name.Replace("=", "").Trim + 'MyBase.TypeId = Mid([Declare], Len(Name) + 1).Trim + 'Me.Expression = Parser.ParseExpression(MyBase.TypeId) + End Sub + + Public Function ToFieldDeclaration() As CodeDom.CodeMemberField + 'Dim CodeMemberField = New CodeDom.CodeMemberField("System.Object", Name) + 'CodeMemberField.Attributes = CodeDom.MemberAttributes.Public + 'Return CodeMemberField + End Function + + Public Overrides Function ToString() As String + ' Return String.Format("Let {0} = {1}", Name, MyBase.TypeId) + End Function + End Class + + Public Module Parser + + Public Function GetPreDeclare(tokens As ClosureTokens(), parent As LINQStatement) As LetClosure() + + End Function + + Public Function GetAfterDeclare(tokens As ClosureTokens(), parent As LINQStatement) As LetClosure() + + End Function + End Module +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/SelectClosure.vb b/LINQ/LINQ/LDM/Expression/SelectClosure.vb new file mode 100644 index 0000000..1a3e659 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/SelectClosure.vb @@ -0,0 +1,33 @@ +Imports System.Text.RegularExpressions +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode.VBC + +Namespace LDM.Expression + + Public Class SelectClosure : Inherits Tokens.Closure + Friend Expression As CodeDom.CodeExpression + Friend SelectMethod As System.Reflection.MethodInfo + + Sub New(tokens As ClosureTokens(), parent As LINQStatement) + Call MyBase.New(TokenIcer.TokenParser.Tokens.Select, tokens, parent) + Call Me.TryParse() + End Sub + + Private Sub TryParse() + 'Dim str = Regex.Match(_statement._Original, " select .+", RegexOptions.IgnoreCase).Value + 'For Each key In Options.OptionList + ' str = Regex.Split(str, String.Format(" {0}\s?", key), RegexOptions.IgnoreCase).First + 'Next + 'str = Mid(str, 9) + 'MyBase._original = str + 'If String.IsNullOrEmpty(str) Then + ' Throw New SyntaxErrorException("Not SELECT statement token, can not procedure the query operation!") + 'End If + 'Me.Expression = New LINQ.Parser.Parser().ParseExpression(str) + End Sub + + Public Sub Initialzie() + SelectMethod = DynamicInvoke.GetMethod(MyBase._statement.ILINQProgram, SelectConstructCompiler.SelectMethodName) + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/LDM/Expression/WhereClosure.vb b/LINQ/LINQ/LDM/Expression/WhereClosure.vb new file mode 100644 index 0000000..412ae78 --- /dev/null +++ b/LINQ/LINQ/LDM/Expression/WhereClosure.vb @@ -0,0 +1,31 @@ +Imports System.CodeDom +Imports System.Reflection +Imports System.Text +Imports System.Text.RegularExpressions +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode +Imports Microsoft.VisualBasic.LINQ.Framework.DynamicCode.VBC + +Namespace LDM.Expression + + Public Class WhereClosure : Inherits Closure + + Friend Expression As CodeExpression + Friend TestMethod As MethodInfo + + Sub New(tokens As ClosureTokens(), parent As LINQStatement) + Call MyBase.New(TokenIcer.TokenParser.Tokens.Where, tokens, parent) + + 'Dim Parser As LINQ.Parser.Parser = New LINQ.Parser.Parser + 'Dim str = GetStatement(Statement._Original, New String() {"where", "let"}, False) + 'If String.IsNullOrEmpty(str) Then + ' str = GetStatement(Statement._Original, New String() {"where", "select"}, False) + 'End If + + 'Expression = Parser.ParseExpression(str) + End Sub + + Public Sub Initialize() + Me.TestMethod = DynamicInvoke.GetMethod(_statement.ILINQProgram, WhereConditionTestCompiler.FunctionName) + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/Statement/Parser/ClosureParser.vb b/LINQ/LINQ/LDM/Parser/ClosureParser.vb similarity index 100% rename from LINQ/LINQ/Statement/Parser/ClosureParser.vb rename to LINQ/LINQ/LDM/Parser/ClosureParser.vb diff --git a/LINQ/LINQ/Statement/Parser/ClosureTokens.vb b/LINQ/LINQ/LDM/Parser/ClosureTokens.vb similarity index 100% rename from LINQ/LINQ/Statement/Parser/ClosureTokens.vb rename to LINQ/LINQ/LDM/Parser/ClosureTokens.vb diff --git a/LINQ/LINQ/Statement/LINQStatement.vb b/LINQ/LINQ/LDM/Parser/LINQStatement.vb similarity index 55% rename from LINQ/LINQ/Statement/LINQStatement.vb rename to LINQ/LINQ/LDM/Parser/LINQStatement.vb index a1f0edf..a209384 100644 --- a/LINQ/LINQ/Statement/LINQStatement.vb +++ b/LINQ/LINQ/LDM/Parser/LINQStatement.vb @@ -24,45 +24,45 @@ Namespace Statements ''' An object element in the target query collection.(目标待查询集合之中的一个元素) ''' ''' - Public Property [Object] As LINQ.Statements.Tokens.FromClosure + Public Property var As FromClosure ''' - ''' Where test condition for the query.(查询所使用的Where条件测试语句) + ''' Target query collection expression, this can be a file path or a database connection string. + ''' (目标待查询集合,值可以为一个文件路径或者数据库连接字符串) ''' ''' ''' ''' - Public Property ConditionTest As LINQ.Statements.Tokens.WhereClosure + Public Property source As InClosure ''' - ''' Target query collection expression, this can be a file path or a database connection string. - ''' (目标待查询集合,值可以为一个文件路径或者数据库连接字符串) + ''' A read only object collection which were construct by the LET statement token in the LINQ statement. + ''' (使用Let语句所构造出来的只读对象类型的对象申明集合) ''' ''' ''' ''' - Public Property Collection As LINQ.Statements.Tokens.InClosure + Public Property PreDeclare As LetClosure() ''' - ''' A read only object collection which were construct by the LET statement token in the LINQ statement. - ''' (使用Let语句所构造出来的只读对象类型的对象申明集合) + ''' Where test condition for the query.(查询所使用的Where条件测试语句) ''' ''' ''' ''' - Public Property ReadOnlyObjects As LINQ.Statements.Tokens.LetClosure() + Public Property Where As WhereClosure + Public Property AfterDeclare As LetClosure() ''' ''' A expression for return the query result.(用于生成查询数据返回的语句) ''' ''' ''' ''' - Public Property SelectConstruct As LINQ.Statements.Tokens.SelectClosure + Public Property SelectClosure As SelectClosure - Friend _Tokens As String() - Friend TypeRegistry As LINQ.Framework.TypeRegistry + Friend TypeRegistry As TypeRegistry ''' ''' 本LINQ脚本对象所编译出来的临时模块 ''' ''' - Friend ILINQProgram As System.Type + Friend ILINQProgram As Type Public ReadOnly Property CompiledCode As String @@ -75,17 +75,21 @@ Namespace Statements ''' Public ReadOnly Property TypeId As String Get - Return [Object].TypeId + Return var.TypeId End Get End Property Public ReadOnly Property IsParallel As Boolean Get - Return Me.Collection.IsParallel + Return Me.source.IsParallel End Get End Property - Public ReadOnly Property Original As String + ''' + ''' Original statement text of this linq expression + ''' + ''' + Public ReadOnly Property Text As String ''' ''' Create a instance for the compiled LINQ statement object model. @@ -97,53 +101,55 @@ Namespace Statements End Function Public Overrides Function ToString() As String - Return Original + Return Text End Function ''' ''' Try to parsing a linq query script into a statement object model and compile the model into a assembly dynamic. ''' (尝试着从所输入的命令语句中解析出一个LINQ查询命令对象,并完成动态编译过程) ''' - ''' + ''' ''' ''' - Public Shared Function TryParse(StatementText As String, registry As TypeRegistry) As LINQStatement - Dim Statement As LINQStatement = New LINQStatement With { - ._Original = StatementText, - ._Tokens = GetTokens(StatementText), - .TypeRegistry = registry + Public Shared Function TryParse(source As String) As LINQStatement + Dim tokens As ClosureTokens() = ClosureParser.TryParse(source) + Dim statement As LINQStatement = New LINQStatement With { + ._Text = source } - Statement.Collection = New InClosure(Statement) - Statement.Object = New FromClosure(Statement) - Statement.ReadOnlyObjects = GetReadOnlyObjects(Statement) - Statement.ConditionTest = New WhereClosure(Statement) - Statement.SelectConstruct = New SelectClosure(Statement) - - Using Compiler As DynamicCompiler = New DynamicCompiler(Statement, SDK_PATH.AvaliableSDK) 'Dynamic code compiling.(动态编译代码) - Dim LINQEntityLibFile As String = Statement.Object.RegistryType.AssemblyFullPath ' - - If Not String.Equals(FileIO.FileSystem.GetParentPath(LINQEntityLibFile), System.Windows.Forms.Application.StartupPath) Then - LINQEntityLibFile = String.Format("{0}\TEMP_LINQ.Entity.lib", System.Windows.Forms.Application.StartupPath) - - If FileIO.FileSystem.FileExists(LINQEntityLibFile) Then - Call FileIO.FileSystem.DeleteFile(LINQEntityLibFile, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) - End If - Call FileIO.FileSystem.CopyFile(Statement.Object.RegistryType.AssemblyFullPath, LINQEntityLibFile) - End If - - Dim ReferenceAssemblys As String() = New String() {LQueryFramework.ReferenceAssembly, LINQEntityLibFile} - Dim CompiledAssembly = Compiler.Compile(ReferenceAssemblys) - Statement.ILINQProgram = DynamicInvoke.GetType(CompiledAssembly, Framework.DynamicCode.VBC.DynamicCompiler.ModuleName).First - Statement._CompiledCode = Compiler.CompiledCode - End Using - - Return Statement.Initialzie + statement.var = New FromClosure(tokens, statement) + statement.source = New InClosure(tokens, statement) + statement.PreDeclare = Parser.GetPreDeclare(tokens, statement) + statement.Where = New WhereClosure(tokens, statement) + statement.AfterDeclare = Parser.GetAfterDeclare(tokens, statement) + statement.SelectClosure = New SelectClosure(tokens, statement) + + Return statement + + 'Using Compiler As DynamicCompiler = New DynamicCompiler(Statement, SDK_PATH.AvaliableSDK) 'Dynamic code compiling.(动态编译代码) + ' Dim LINQEntityLibFile As String = Statement.Object.RegistryType.AssemblyFullPath ' + + ' If Not String.Equals(FileIO.FileSystem.GetParentPath(LINQEntityLibFile), System.Windows.Forms.Application.StartupPath) Then + ' LINQEntityLibFile = String.Format("{0}\TEMP_LINQ.Entity.lib", System.Windows.Forms.Application.StartupPath) + + ' If FileIO.FileSystem.FileExists(LINQEntityLibFile) Then + ' Call FileIO.FileSystem.DeleteFile(LINQEntityLibFile, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) + ' End If + ' Call FileIO.FileSystem.CopyFile(Statement.Object.RegistryType.AssemblyFullPath, LINQEntityLibFile) + ' End If + + ' Dim ReferenceAssemblys As String() = New String() {LQueryFramework.ReferenceAssembly, LINQEntityLibFile} + ' Dim CompiledAssembly = Compiler.Compile(ReferenceAssemblys) + ' Statement.ILINQProgram = DynamicInvoke.GetType(CompiledAssembly, Framework.DynamicCode.VBC.DynamicCompiler.ModuleName).First + ' Statement._CompiledCode = Compiler.CompiledCode + 'End Using + + 'Return Statement.Initialzie End Function Private Function Initialzie() As LINQStatement - Call [Object].Initialize() - Call ConditionTest.Initialize() - Call SelectConstruct.Initialzie() + Call var.Initialize() + Call Where.Initialize() + Call SelectClosure.Initialzie() Return Me End Function End Class diff --git a/LINQ/LINQ/Statement/Tokens/Closure.vb b/LINQ/LINQ/LDM/Parser/Tokens/Closure.vb similarity index 77% rename from LINQ/LINQ/Statement/Tokens/Closure.vb rename to LINQ/LINQ/LDM/Parser/Tokens/Closure.vb index 22d8b03..27e08b9 100644 --- a/LINQ/LINQ/Statement/Tokens/Closure.vb +++ b/LINQ/LINQ/LDM/Parser/Tokens/Closure.vb @@ -5,15 +5,10 @@ Namespace Statements.Tokens Public MustInherit Class Closure Protected _statement As LINQStatement - Protected _tokens As ClosureTokens() - ''' - ''' 的第一个元素 - ''' Protected _source As ClosureTokens Sub New(type As TokenParser.Tokens, tokens As ClosureTokens(), parent As LINQStatement) - _tokens = GetTokens(type, from:=tokens) - _source = _tokens.FirstOrDefault + _source = GetTokens(type, from:=tokens) _statement = parent If _source Is Nothing Then @@ -29,14 +24,19 @@ Namespace Statements.Tokens End If End Sub + Sub New(token As ClosureTokens, parent As LINQStatement) + _source = token + _statement = parent + End Sub + Const MissingRequiredField As String = "Missing the required LINQ statement token {0}!" Public Overrides Function ToString() As String - Return _tokens.ToString + Return _source.ToString End Function - Public Shared Function GetTokens(type As TokenParser.Tokens, from As ClosureTokens()) As ClosureTokens() - Dim LQuery = (From x As ClosureTokens In from Where x.Token = type Select x).ToArray + Public Shared Function GetTokens(type As TokenParser.Tokens, from As ClosureTokens()) As ClosureTokens + Dim LQuery = (From x As ClosureTokens In from Where x.Token = type Select x).FirstOrDefault Return LQuery End Function End Class diff --git a/LINQ/LINQ/Statement/Tokens/FromClosure.vb b/LINQ/LINQ/LDM/Parser/Tokens/FromClosure.vb similarity index 64% rename from LINQ/LINQ/Statement/Tokens/FromClosure.vb rename to LINQ/LINQ/LDM/Parser/Tokens/FromClosure.vb index 2118928..21e24bd 100644 --- a/LINQ/LINQ/Statement/Tokens/FromClosure.vb +++ b/LINQ/LINQ/LDM/Parser/Tokens/FromClosure.vb @@ -5,6 +5,9 @@ Imports Microsoft.VisualBasic.LINQ.Framework.LQueryFramework Namespace Statements.Tokens + ''' + ''' The init variable. + ''' Public Class FromClosure : Inherits Closure ''' @@ -28,23 +31,15 @@ Namespace Statements.Tokens Sub New(tokens As ClosureTokens(), parent As LINQStatement) Call MyBase.New(TokenIcer.TokenParser.Tokens.From, tokens, parent) - Me.TryParse() - Me.RegistryType = Statement.TypeRegistry.Find(TypeId) - If RegistryType Is Nothing Then - Throw New TypeMissingExzception("Could not found any information about the type {0}.", TypeId) - Else - Dim ILINQCollection As System.Type = _tokens.ObjectCollection.LoadExternalModule(RegistryType) - Statement.Collection.ILINQCollection = Activator.CreateInstance(ILINQCollection) - Me.TypeId = Statement.Collection.ILINQCollection.GetEntityType.FullName - End If - End Sub - Private Sub TryParse() - Dim str = GetStatement(_statement._Original, New String() {"from", "in"}, True) - Dim Tokens As String() = str.Split - Name = Tokens.First - TypeId = Tokens.Last - Me._original = str + 'Me.RegistryType = Statement.TypeRegistry.Find(TypeId) + 'If RegistryType Is Nothing Then + ' Throw New TypeMissingExzception("Could not found any information about the type {0}.", TypeId) + 'Else + ' Dim ILINQCollection As System.Type = _tokens.ObjectCollection.LoadExternalModule(RegistryType) + ' Statement.Collection.ILINQCollection = Activator.CreateInstance(ILINQCollection) + ' Me.TypeId = Statement.Collection.ILINQCollection.GetEntityType.FullName + 'End If End Sub Public Overridable Function ToFieldDeclaration() As CodeDom.CodeMemberField diff --git a/LINQ/LINQ/Statement/Tokens/InClosure.vb b/LINQ/LINQ/LDM/Parser/Tokens/InClosure.vb similarity index 79% rename from LINQ/LINQ/Statement/Tokens/InClosure.vb rename to LINQ/LINQ/LDM/Parser/Tokens/InClosure.vb index 4061916..c3383c5 100644 --- a/LINQ/LINQ/Statement/Tokens/InClosure.vb +++ b/LINQ/LINQ/LDM/Parser/Tokens/InClosure.vb @@ -50,30 +50,20 @@ Namespace Statements.Tokens ''' Public ReadOnly Property Value As String Get - Return _original + ' Return _original End Get End Property Sub New(tokens As ClosureTokens(), parent As LINQStatement) Call MyBase.New(TokenIcer.TokenParser.Tokens.In, tokens, parent) - Call Me.TryParse() - End Sub - - Private Sub TryParse() - For i As Integer = 0 To _statement._Tokens.Count - 1 - If String.Equals("In", _statement._Tokens(i), StringComparison.OrdinalIgnoreCase) Then - Me._original = _statement._Tokens(i + 1) - Return - End If - Next End Sub Public Overrides Function ToString() As String - If Type = CollectionTypes.File Then - Return String.Format("(File) {0}", Me._original) - Else - Return Type.ToString - End If + 'If Type = CollectionTypes.File Then + ' Return String.Format("(File) {0}", Me._original) + 'Else + ' Return Type.ToString + 'End If End Function ''' diff --git a/LINQ/LINQ/LDM/Parser/Tokens/LetClosure.vb b/LINQ/LINQ/LDM/Parser/Tokens/LetClosure.vb new file mode 100644 index 0000000..19877f0 --- /dev/null +++ b/LINQ/LINQ/LDM/Parser/Tokens/LetClosure.vb @@ -0,0 +1,47 @@ +Imports System.Text.RegularExpressions +Imports System.Text + +Namespace Statements.Tokens + + ''' + ''' Object declared using a LET expression.(使用Let语句所声明的只读对象) + ''' + ''' + Public Class LetClosure : Inherits Closure + + Friend Expression As CodeDom.CodeExpression + + ''' + ''' + ''' + ''' + Sub New(token As ClosureTokens, parent As LINQStatement) + Call MyBase.New(token, parent) + 'Dim Name As String = Regex.Match([Declare], ".+?\=").Value + 'MyBase.Name = Name.Replace("=", "").Trim + 'MyBase.TypeId = Mid([Declare], Len(Name) + 1).Trim + 'Me.Expression = Parser.ParseExpression(MyBase.TypeId) + End Sub + + Public Function ToFieldDeclaration() As CodeDom.CodeMemberField + 'Dim CodeMemberField = New CodeDom.CodeMemberField("System.Object", Name) + 'CodeMemberField.Attributes = CodeDom.MemberAttributes.Public + 'Return CodeMemberField + End Function + + Public Overrides Function ToString() As String + ' Return String.Format("Let {0} = {1}", Name, MyBase.TypeId) + End Function + End Class + + Public Module Parser + + Public Function GetPreDeclare(tokens As ClosureTokens(), parent As LINQStatement) As LetClosure() + + End Function + + Public Function GetAfterDeclare(tokens As ClosureTokens(), parent As LINQStatement) As LetClosure() + + End Function + End Module +End Namespace \ No newline at end of file diff --git a/LINQ/LINQ/Statement/Tokens/Options.vb b/LINQ/LINQ/LDM/Parser/Tokens/Options.vb similarity index 100% rename from LINQ/LINQ/Statement/Tokens/Options.vb rename to LINQ/LINQ/LDM/Parser/Tokens/Options.vb diff --git a/LINQ/LINQ/Statement/Tokens/SelectClosure.vb b/LINQ/LINQ/LDM/Parser/Tokens/SelectClosure.vb similarity index 55% rename from LINQ/LINQ/Statement/Tokens/SelectClosure.vb rename to LINQ/LINQ/LDM/Parser/Tokens/SelectClosure.vb index c6a0665..f172343 100644 --- a/LINQ/LINQ/Statement/Tokens/SelectClosure.vb +++ b/LINQ/LINQ/LDM/Parser/Tokens/SelectClosure.vb @@ -10,21 +10,20 @@ Namespace Statements.Tokens Sub New(tokens As ClosureTokens(), parent As LINQStatement) Call MyBase.New(TokenIcer.TokenParser.Tokens.Select, tokens, parent) - MyBase._statement = Statement Call Me.TryParse() End Sub Private Sub TryParse() - Dim str = Regex.Match(_statement._Original, " select .+", RegexOptions.IgnoreCase).Value - For Each key In Options.OptionList - str = Regex.Split(str, String.Format(" {0}\s?", key), RegexOptions.IgnoreCase).First - Next - str = Mid(str, 9) - MyBase._original = str - If String.IsNullOrEmpty(str) Then - Throw New SyntaxErrorException("Not SELECT statement token, can not procedure the query operation!") - End If - Me.Expression = New LINQ.Parser.Parser().ParseExpression(str) + 'Dim str = Regex.Match(_statement._Original, " select .+", RegexOptions.IgnoreCase).Value + 'For Each key In Options.OptionList + ' str = Regex.Split(str, String.Format(" {0}\s?", key), RegexOptions.IgnoreCase).First + 'Next + 'str = Mid(str, 9) + 'MyBase._original = str + 'If String.IsNullOrEmpty(str) Then + ' Throw New SyntaxErrorException("Not SELECT statement token, can not procedure the query operation!") + 'End If + 'Me.Expression = New LINQ.Parser.Parser().ParseExpression(str) End Sub Public Sub Initialzie() diff --git a/LINQ/LINQ/Statement/Tokens/WhereClosure.vb b/LINQ/LINQ/LDM/Parser/Tokens/WhereClosure.vb similarity index 63% rename from LINQ/LINQ/Statement/Tokens/WhereClosure.vb rename to LINQ/LINQ/LDM/Parser/Tokens/WhereClosure.vb index 13d891d..9883250 100644 --- a/LINQ/LINQ/Statement/Tokens/WhereClosure.vb +++ b/LINQ/LINQ/LDM/Parser/Tokens/WhereClosure.vb @@ -14,15 +14,14 @@ Namespace Statements.Tokens Sub New(tokens As ClosureTokens(), parent As LINQStatement) Call MyBase.New(TokenIcer.TokenParser.Tokens.Where, tokens, parent) - Me._statement = Statement - Dim Parser As LINQ.Parser.Parser = New LINQ.Parser.Parser - Dim str = GetStatement(Statement._Original, New String() {"where", "let"}, False) - If String.IsNullOrEmpty(str) Then - str = GetStatement(Statement._Original, New String() {"where", "select"}, False) - End If + 'Dim Parser As LINQ.Parser.Parser = New LINQ.Parser.Parser + 'Dim str = GetStatement(Statement._Original, New String() {"where", "let"}, False) + 'If String.IsNullOrEmpty(str) Then + ' str = GetStatement(Statement._Original, New String() {"where", "select"}, False) + 'End If - Expression = Parser.ParseExpression(str) + 'Expression = Parser.ParseExpression(str) End Sub Public Sub Initialize() diff --git a/LINQ/LINQ/LINQ.vbproj b/LINQ/LINQ/LINQ.vbproj index 834cabc..c439adc 100644 --- a/LINQ/LINQ/LINQ.vbproj +++ b/LINQ/LINQ/LINQ.vbproj @@ -116,8 +116,15 @@ - - + + + + + + + + + @@ -139,7 +146,7 @@ - + True @@ -155,13 +162,13 @@ Settings.settings True - - - - - - - + + + + + + + diff --git a/LINQ/LINQ/Statement/Tokens/LetClosure.vb b/LINQ/LINQ/Statement/Tokens/LetClosure.vb deleted file mode 100644 index b653fd7..0000000 --- a/LINQ/LINQ/Statement/Tokens/LetClosure.vb +++ /dev/null @@ -1,100 +0,0 @@ -Imports System.Text.RegularExpressions -Imports System.Text - -Namespace Statements.Tokens - - ''' - ''' Object declared using a LET expression.(使用Let语句所声明的只读对象) - ''' - ''' - Public Class LetClosure : Inherits Closure - - Friend Expression As CodeDom.CodeExpression - - ''' - ''' - ''' - ''' - Sub New(tokens As ClosureTokens(), parent As LINQStatement) - Call MyBase.New(TokenIcer.TokenParser.Tokens.Let, tokens, parent) - Dim Name As String = Regex.Match([Declare], ".+?\=").Value - MyBase.Name = Name.Replace("=", "").Trim - MyBase.TypeId = Mid([Declare], Len(Name) + 1).Trim - Me.Expression = Parser.ParseExpression(MyBase.TypeId) - End Sub - - Public Overrides Function ToFieldDeclaration() As CodeDom.CodeMemberField - Dim CodeMemberField = New CodeDom.CodeMemberField("System.Object", Name) - CodeMemberField.Attributes = CodeDom.MemberAttributes.Public - Return CodeMemberField - End Function - - Public Overrides Function ToString() As String - Return String.Format("Let {0} = {1}", Name, MyBase.TypeId) - End Function - End Class - - Public Module Parser - - Public Function GetStatement(s As String, Tokens As String(), LTrimb As Boolean) As String - Dim str As String = String.Format(" {0} .+ {1} ", Tokens(0), Tokens(1)) - Dim nL As Integer = 2 - If LTrimb Then - str = LTrim(str) - nL = 1 - End If - Dim sBuilder As StringBuilder = New StringBuilder(Regex.Match(s, str, RegexOptions.IgnoreCase).Value) - - If sBuilder.Length > 0 Then - Call sBuilder.Remove(0, nL + Len(Tokens(0))) - Dim n = Len(Tokens(1)) + 2 - Call sBuilder.Remove(sBuilder.Length - n, n) - - Return sBuilder.ToString - Else - Return "" - End If - End Function - - ''' - ''' 获取Let只读对象的申明语句 - ''' - ''' - ''' - Private Function GetLetStatements(Statement As LINQ.Statements.LINQStatement) As String() - Dim str As String = GetStatement(Statement._Original, New String() {"let", "where"}, False) - If String.IsNullOrEmpty(str) Then - str = GetStatement(Statement._Original, New String() {"let", "select"}, False) - If String.IsNullOrEmpty(str) Then - Return New String() {} - End If - End If - - Dim objs = Strings.Split(str, " let ", -1, CompareMethod.Text).ToList - str = GetStatement(Statement._Original, New String() {"where", "select"}, False) - If Not String.IsNullOrEmpty(str) Then - Dim sBuilder As StringBuilder = New StringBuilder(Regex.Match(str, " let .+", RegexOptions.IgnoreCase).Value) - If sBuilder.Length = 0 Then - Return objs.ToArray - Else - sBuilder.Remove(0, 5) - Call objs.AddRange(Strings.Split(sBuilder.ToString, " let ", -1, CompareMethod.Text)) - End If - End If - - Return objs.ToArray - End Function - - Public Function GetReadOnlyObjects(Statement As LINQ.Statements.LINQStatement) As LINQ.Statements.Tokens.FromClosure() - Dim LetStatements As String() = GetLetStatements(Statement) - Dim Parser As LINQ.Parser.Parser = New LINQ.Parser.Parser - Dim ReadOnlyObjectList As List(Of Statements.Tokens.LetClosure) = New List(Of Tokens.LetClosure) - For Each obj In LetStatements - Dim ReadOnlyObject As Tokens.LetClosure = New Tokens.LetClosure(Statement, Parser, obj) - Call ReadOnlyObjectList.Add(ReadOnlyObject) - Next - - Return ReadOnlyObjectList.ToArray - End Function - End Module -End Namespace \ No newline at end of file