[Tween-svn] [1322] ラムダ式による振り分けがとりあえず動作するようになった 使用するにはSettingTabs . XmlのFiltersClass . UseLambdaをTrueへ書き換える必要がある it . プロパティ名 でPostClassの各プロパティが参照可能

Back to archive index

svnno****@sourc***** svnno****@sourc*****
2011年 1月 6日 (木) 08:31:47 JST


Revision: 1322
          http://sourceforge.jp/projects/tween/svn/view?view=rev&revision=1322
Author:   syo68k
Date:     2011-01-06 08:31:47 +0900 (Thu, 06 Jan 2011)

Log Message:
-----------
ラムダ式による振り分けがとりあえず動作するようになった 使用するにはSettingTabs.XmlのFiltersClass.UseLambdaをTrueへ書き換える必要がある it.プロパティ名 でPostClassの各プロパティが参照可能

Modified Paths:
--------------
    branches/query/Tween/StatusDictionary.vb
    branches/query/Tween/Tween.vbproj
    branches/query/Tween.sln

Added Paths:
-----------
    branches/query/Tween/Dynamic.vb


-------------- next part --------------
Added: branches/query/Tween/Dynamic.vb
===================================================================
--- branches/query/Tween/Dynamic.vb	                        (rev 0)
+++ branches/query/Tween/Dynamic.vb	2011-01-05 23:31:47 UTC (rev 1322)
@@ -0,0 +1,1947 @@
+' Copyright © Microsoft Corporation.  All Rights Reserved.
+' This code released under the terms of the 
+' Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)
+'
+Option Strict On
+Option Explicit On
+
+Imports System.Collections.Generic
+Imports System.Text
+Imports System.Linq
+Imports System.Linq.Expressions
+Imports System.Reflection
+Imports System.Reflection.Emit
+Imports System.Threading
+Imports System.Runtime.CompilerServices
+
+
+Public Module DynamicQueryable
+
+    Const Id As String = "DynamicQueryModule Copyright © Microsoft Corporation.  All Rights Reserved." + _
+                         "This code released under the terms of the Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) "
+
+    <Extension()> _
+    Public Function Where(Of T)(ByVal source As IQueryable(Of T), ByVal predicate As String, ByVal ParamArray values() As Object) As IQueryable(Of T)
+        Return DirectCast(Where(DirectCast(source, IQueryable), predicate, values), IQueryable(Of T))
+    End Function
+
+    <Extension()> _
+    Public Function Where(ByVal source As IQueryable, ByVal predicate As String, ByVal ParamArray values() As Object) As IQueryable
+        If source Is Nothing Then Throw New ArgumentNullException("source")
+        If predicate Is Nothing Then Throw New ArgumentNullException("predicate")
+        Dim lambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, GetType(Boolean), predicate, values)
+        Return source.Provider.CreateQuery( _
+                                           Expression.Call( _
+                                                           GetType(Queryable), "Where", _
+                                                           New Type() {source.ElementType}, _
+                                                           source.Expression, Expression.Quote(lambda)))
+    End Function
+
+    <Extension()> _
+    Public Function [Select](ByVal source As IQueryable, ByVal selector As String, ByVal ParamArray values() As Object) As IQueryable
+        If source Is Nothing Then Throw New ArgumentNullException("source")
+        If selector Is Nothing Then Throw New ArgumentNullException("selector")
+        Dim lambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, Nothing, selector, values)
+        Return source.Provider.CreateQuery( _
+                                           Expression.Call( _
+                                                           GetType(Queryable), "Select", _
+                                                           New Type() {source.ElementType, lambda.Body.Type}, _
+                                                           source.Expression, Expression.Quote(lambda)))
+    End Function
+
+    <Extension()> _
+    Public Function OrderBy(Of T)(ByVal source As IQueryable(Of T), ByVal ordering As String, ByVal ParamArray values() As Object) As IQueryable(Of T)
+        Return DirectCast(OrderBy(DirectCast(source, IQueryable), ordering, values), IQueryable(Of T))
+    End Function
+
+    <Extension()> _
+    Public Function OrderBy(ByVal source As IQueryable, ByVal ordering As String, ByVal ParamArray values() As Object) As IQueryable
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        If (ordering Is Nothing) Then Throw New ArgumentNullException("ordering")
+        Dim parameters = New ParameterExpression() { _
+                                                       Expression.Parameter(source.ElementType, "")}
+        Dim parser As New ExpressionParser(parameters, ordering, values)
+        Dim orderings As IEnumerable(Of DynamicOrdering) = parser.ParseOrdering()
+        Dim queryExpr As Expression = source.Expression
+        Dim methodAsc = "OrderBy"
+        Dim methodDesc = "OrderByDescending"
+        For Each o As DynamicOrdering In orderings
+            queryExpr = Expression.Call( _
+                                        GetType(Queryable), If(o.Ascending, methodAsc, methodDesc), _
+                                        New Type() {source.ElementType, o.Selector.Type}, _
+                                        queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)))
+            methodAsc = "ThenBy"
+            methodDesc = "ThenByDescending"
+        Next o
+        Return source.Provider.CreateQuery(queryExpr)
+    End Function
+
+    <Extension()> _
+    Public Function Take(ByVal source As IQueryable, ByVal count As Integer) As IQueryable
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        Return source.Provider.CreateQuery( _
+                                           Expression.Call( _
+                                                           GetType(Queryable), "Take", _
+                                                           New Type() {source.ElementType}, _
+                                                           source.Expression, Expression.Constant(count)))
+    End Function
+
+    <Extension()> _
+    Public Function Skip(ByVal source As IQueryable, ByVal count As Integer) As IQueryable
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        Return source.Provider.CreateQuery( _
+                                           Expression.Call( _
+                                                           GetType(Queryable), "Skip", _
+                                                           New Type() {source.ElementType}, _
+                                                           source.Expression, Expression.Constant(count)))
+    End Function
+
+    <Extension()> _
+    Public Function GroupBy(ByVal source As IQueryable, ByVal keySelector As String, ByVal elementSelector As String, ByVal ParamArray values() As Object) As IQueryable
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        If (keySelector Is Nothing) Then Throw New ArgumentNullException("keySelector")
+        If (elementSelector Is Nothing) Then Throw New ArgumentNullException("elementSelector")
+        Dim keyLambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, Nothing, keySelector, values)
+        Dim elementLambda As LambdaExpression = DynamicExpression.ParseLambda(source.ElementType, Nothing, elementSelector, values)
+        Return source.Provider.CreateQuery( _
+                                           Expression.Call( _
+                                                           GetType(Queryable), "GroupBy", _
+                                                           New Type() {source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type}, _
+                                                           source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)))
+    End Function
+
+    <Extension()> _
+    Public Function Any(ByVal source As IQueryable) As Boolean
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        Return CBool(source.Provider.Execute( _
+                                             Expression.Call( _
+                                                             GetType(Queryable), "Any", _
+                                                             New Type() {source.ElementType}, source.Expression)))
+    End Function
+
+    <Extension()> _
+    Public Function Count(ByVal source As IQueryable) As Integer
+        If (source Is Nothing) Then Throw New ArgumentNullException("source")
+        Return CInt(source.Provider.Execute( _
+                                            Expression.Call( _
+                                                            GetType(Queryable), "Count", _
+                                                            New Type() {source.ElementType}, source.Expression)))
+    End Function
+End Module
+
+Public MustInherit Class DynamicClass
+    Public Overrides Function ToString() As String
+        Dim props = Me.GetType().GetProperties(BindingFlags.Instance Or BindingFlags.Public)
+        Dim sb As New StringBuilder()
+        sb.Append("{")
+        For i As Integer = 0 To props.Length - 1
+            If (i > 0) Then sb.Append(", ")
+            sb.Append(props(i).Name)
+            sb.Append("=")
+            sb.Append(props(i).GetValue(Me, Nothing))
+        Next i
+
+        sb.Append("}")
+
+        Return sb.ToString()
+    End Function
+End Class
+
+Public Class DynamicProperty
+    Private _name As String
+    Private _type As Type
+
+    Public Sub New(ByVal name As String, ByVal type As Type)
+        If (name Is Nothing) Then Throw New ArgumentNullException("name")
+        If (type Is Nothing) Then Throw New ArgumentNullException("type")
+        Me._name = name
+        Me._type = type
+    End Sub
+
+    Public ReadOnly Property Name() As String
+        Get
+            Return _name
+        End Get
+    End Property
+
+    Public ReadOnly Property Type() As Type
+        Get
+            Return _type
+        End Get
+    End Property
+End Class
+
+Public Module DynamicExpression
+    Public Function Parse(ByVal resultType As Type, ByVal expression As String, ByVal ParamArray values() As Object) As Expression
+        Dim parser As New ExpressionParser(Nothing, expression, values)
+        Return parser.Parse(resultType)
+    End Function
+
+    Public Function ParseLambda(ByVal itType As Type, ByVal resultType As Type, ByVal expressionStr As String, ByVal ParamArray values() As Object) As LambdaExpression
+        Return ParseLambda(New ParameterExpression() {Expression.Parameter(itType, "")}, resultType, expressionStr, values)
+    End Function
+
+    Public Function ParseLambda(ByVal parameters() As ParameterExpression, ByVal resultType As Type, ByVal expressionStr As String, ByVal ParamArray values() As Object) As LambdaExpression
+        Dim parser As New ExpressionParser(parameters, expressionStr, values)
+        Return Expression.Lambda(parser.Parse(resultType), parameters)
+    End Function
+
+    Public Function ParseLambda(Of T, S)(ByVal expression As String, ByVal ParamArray values() As Object) As Expression(Of Func(Of T, S))
+        Return DirectCast(ParseLambda(GetType(T), GetType(S), expression, values), Expression(Of Func(Of T, S)))
+    End Function
+
+    Public Function CreateClass(ByVal ParamArray properties() As DynamicProperty) As Type
+        Return ClassFactory.Instance.GetDynamicClass(properties)
+    End Function
+
+    Public Function CreateClass(ByVal properties As IEnumerable(Of DynamicProperty)) As Type
+        Return ClassFactory.Instance.GetDynamicClass(properties)
+    End Function
+End Module
+
+Friend Class DynamicOrdering
+    Public Selector As Expression
+    Public Ascending As Boolean
+End Class
+
+Friend Class Signature : Implements IEquatable(Of Signature)
+    Public properties() As DynamicProperty
+    Public hashCode As Integer
+
+    Public Sub New(ByVal properties As IEnumerable(Of DynamicProperty))
+        Me.properties = properties.ToArray()
+        hashCode = 0
+        For Each p As DynamicProperty In Me.properties
+            hashCode = hashCode Xor p.Name.GetHashCode() Xor p.Type.GetHashCode()
+        Next p
+    End Sub
+
+    Public Overrides Function GetHashCode() As Integer
+        Return hashCode
+    End Function
+
+    Public Overrides Function Equals(ByVal obj As Object) As Boolean
+        Dim cast = TryCast(obj, Signature)
+        Return If(cast IsNot Nothing, Equals(cast), False)
+    End Function
+
+    Public Overloads Function Equals(ByVal other As Signature) As Boolean Implements IEquatable(Of Signature).Equals
+        If (properties.Length <> other.properties.Length) Then Return False
+        For i As Integer = 0 To properties.Length - 1
+            If (properties(i).Name <> other.properties(i).Name OrElse _
+                Not properties(i).Type.Equals(other.properties(i).Type)) Then
+                Return False
+            End If
+        Next i
+        Return True
+    End Function
+End Class
+
+Friend Class ClassFactory
+    Public Shared ReadOnly Instance As New ClassFactory()
+
+    Shared Sub New()
+        ' Trigger lazy initialization of static fields
+    End Sub
+
+    Private [module] As ModuleBuilder
+    Private classes As Dictionary(Of Signature, Type)
+    Private classCount As Integer
+    Private rwLock As ReaderWriterLock
+
+    Private Sub New()
+        Dim name As New AssemblyName("DynamicClasses")
+        Dim assembly As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run)
+#If ENABLE_LINQ_PARTIAL_TRUST Then
+            call new ReflectionPermission(PermissionState.Unrestricted).Assert()
+#End If
+        Try
+            [module] = assembly.DefineDynamicModule("Module")
+        Finally
+#If ENABLE_LINQ_PARTIAL_TRUST Then
+                PermissionSet.RevertAssert()
+#End If
+        End Try
+        classes = New Dictionary(Of Signature, Type)()
+        rwLock = New ReaderWriterLock()
+    End Sub
+
+    Public Function GetDynamicClass(ByVal properties As IEnumerable(Of DynamicProperty)) As Type
+        rwLock.AcquireReaderLock(Timeout.Infinite)
+
+        Try
+            Dim signature As New Signature(properties)
+            Dim type As Type = Nothing
+            If Not classes.TryGetValue(signature, type) Then
+                type = CreateDynamicClass(signature.properties)
+                classes.Add(signature, type)
+            End If
+            Return type
+        Finally
+            rwLock.ReleaseReaderLock()
+        End Try
+    End Function
+
+    Private Function CreateDynamicClass(ByVal properties() As DynamicProperty) As Type
+        Dim cookie As LockCookie = rwLock.UpgradeToWriterLock(Timeout.Infinite)
+        Try
+            Dim typeName = "DynamicClass" & (classCount + 1)
+#If ENABLE_LINQ_PARTIAL_TRUST Then
+                Call New ReflectionPermission(PermissionState.Unrestricted).Assert()
+#End If
+            Try
+                Dim tb As TypeBuilder = Me.module.DefineType(typeName, TypeAttributes.Class Or _
+                                                                       TypeAttributes.Public, GetType(DynamicClass))
+                Dim fields() As FieldInfo = GenerateProperties(tb, properties)
+                GenerateEquals(tb, fields)
+                GenerateGetHashCode(tb, fields)
+                Dim result As Type = tb.CreateType()
+                classCount += 1
+                Return result
+            Finally
+#If ENABLE_LINQ_PARTIAL_TRUST Then
+                    PermissionSet.RevertAssert()
+#End If
+            End Try
+        Finally
+            rwLock.DowngradeFromWriterLock(cookie)
+        End Try
+    End Function
+
+    Private Function GenerateProperties(ByVal tb As TypeBuilder, ByVal properties() As DynamicProperty) As FieldInfo()
+        Dim fields(properties.Length - 1) As FieldInfo
+
+        For i As Integer = 0 To properties.Length - 1
+            Dim dp As DynamicProperty = properties(i)
+            Dim fb As FieldBuilder = tb.DefineField("_" & dp.Name, dp.Type, FieldAttributes.Private)
+            Dim pb As PropertyBuilder = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, Nothing)
+            Dim mbGet As MethodBuilder = tb.DefineMethod("get_" + dp.Name, _
+                                                         MethodAttributes.Public Or MethodAttributes.SpecialName Or MethodAttributes.HideBySig, _
+                                                         dp.Type, System.Type.EmptyTypes)
+            Dim genGet As ILGenerator = mbGet.GetILGenerator()
+            genGet.Emit(OpCodes.Ldarg_0)
+            genGet.Emit(OpCodes.Ldfld, fb)
+            genGet.Emit(OpCodes.Ret)
+            Dim mbSet As MethodBuilder = tb.DefineMethod("set_" & dp.Name, _
+                                                         MethodAttributes.Public Or MethodAttributes.SpecialName Or MethodAttributes.HideBySig, _
+                                                         Nothing, New Type() {dp.Type})
+            Dim genSet As ILGenerator = mbSet.GetILGenerator()
+            genSet.Emit(OpCodes.Ldarg_0)
+            genSet.Emit(OpCodes.Ldarg_1)
+            genSet.Emit(OpCodes.Stfld, fb)
+            genSet.Emit(OpCodes.Ret)
+            pb.SetGetMethod(mbGet)
+            pb.SetSetMethod(mbSet)
+            fields(i) = fb
+        Next i
+
+        Return fields
+    End Function
+
+    Private Sub GenerateEquals(ByVal tb As TypeBuilder, ByVal fields As FieldInfo())
+        Dim mb As MethodBuilder = tb.DefineMethod("Equals", _
+                                                  MethodAttributes.Public Or MethodAttributes.ReuseSlot Or _
+                                                  MethodAttributes.Virtual Or MethodAttributes.HideBySig, _
+                                                  GetType(Boolean), New Type() {GetType(Object)})
+        Dim gen As ILGenerator = mb.GetILGenerator()
+        Dim other As LocalBuilder = gen.DeclareLocal(tb)
+        Dim [next] As Label = gen.DefineLabel()
+        gen.Emit(OpCodes.Ldarg_1)
+        gen.Emit(OpCodes.Isinst, tb)
+        gen.Emit(OpCodes.Stloc, other)
+        gen.Emit(OpCodes.Ldloc, other)
+        gen.Emit(OpCodes.Brtrue_S, [next])
+        gen.Emit(OpCodes.Ldc_I4_0)
+        gen.Emit(OpCodes.Ret)
+        gen.MarkLabel([next])
+        For Each field As FieldInfo In fields
+            Dim ft As Type = field.FieldType
+            Dim ct As Type = GetType(EqualityComparer(Of Object)).GetGenericTypeDefinition().MakeGenericType(ft)
+            [next] = gen.DefineLabel()
+            gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), Nothing)
+            gen.Emit(OpCodes.Ldarg_0)
+            gen.Emit(OpCodes.Ldfld, field)
+            gen.Emit(OpCodes.Ldloc, other)
+            gen.Emit(OpCodes.Ldfld, field)
+            gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", New Type() {ft, ft}), Nothing)
+            gen.Emit(OpCodes.Brtrue_S, [next])
+            gen.Emit(OpCodes.Ldc_I4_0)
+            gen.Emit(OpCodes.Ret)
+            gen.MarkLabel([next])
+        Next
+        gen.Emit(OpCodes.Ldc_I4_1)
+        gen.Emit(OpCodes.Ret)
+    End Sub
+
+    Private Sub GenerateGetHashCode(ByVal tb As TypeBuilder, ByVal fields As FieldInfo())
+        Dim mb As MethodBuilder = tb.DefineMethod("GetHashCode", _
+                                                  MethodAttributes.Public Or MethodAttributes.ReuseSlot Or _
+                                                  MethodAttributes.Virtual Or MethodAttributes.HideBySig, _
+                                                  GetType(Integer), System.Type.EmptyTypes)
+        Dim gen As ILGenerator = mb.GetILGenerator()
+        gen.Emit(OpCodes.Ldc_I4_0)
+        For Each field As FieldInfo In fields
+            Dim ft As Type = field.FieldType
+            Dim ct As Type = GetType(EqualityComparer(Of Object)).GetGenericTypeDefinition().MakeGenericType(ft)
+            gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), Nothing)
+            gen.Emit(OpCodes.Ldarg_0)
+            gen.Emit(OpCodes.Ldfld, field)
+            gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", New Type() {ft}), Nothing)
+            gen.Emit(OpCodes.Xor)
+        Next
+        gen.Emit(OpCodes.Ret)
+    End Sub
+End Class
+
+Public NotInheritable Class ParseException : Inherits Exception
+    Private positionValue As Integer
+
+    Public Sub New(ByVal message As String, ByVal position As Integer)
+        MyBase.New(message)
+        Me.positionValue = position
+    End Sub
+
+    Public ReadOnly Property Position() As Integer
+        Get
+            Return positionValue
+        End Get
+    End Property
+
+    Public Overrides Function ToString() As String
+        Return String.Format(Res.ParseExceptionFormat, Message, Position)
+    End Function
+End Class
+
+Class ExpressionParser
+    Structure Token
+        Public id As TokenId
+        Public text As String
+        Public pos As Integer
+    End Structure
+
+    Enum TokenId
+        Unknown
+        [End]
+        Identifier
+        StringLiteral
+        IntegerLiteral
+        RealLiteral
+        Exclamation
+        Percent
+        Amphersand
+        OpenParen
+        CloseParen
+        Asterisk
+        Plus
+        Comma
+        Minus
+        Dot
+        Slash
+        Colon
+        LessThan
+        Equal
+        GreaterThan
+        Question
+        OpenBracket
+        CloseBracket
+        Bar
+        ExclamationEqual
+        DoubleAmphersand
+        LessThanEqual
+        LessGreater
+        DoubleEqual
+        GreaterThanEqual
+        DoubleBar
+    End Enum
+
+    Interface ILogicalSignatures
+        Sub F(ByVal x As Boolean, ByVal y As Boolean)
+        Sub F(ByVal x? As Boolean, ByVal y? As Boolean)
+    End Interface
+
+    Interface IArithmeticSignatures
+        Sub F(ByVal x As Integer, ByVal y As Integer)
+        Sub F(ByVal x As UInteger, ByVal y As UInteger)
+        Sub F(ByVal x As Long, ByVal y As Long)
+        Sub F(ByVal x As ULong, ByVal y As ULong)
+        Sub F(ByVal x As Single, ByVal y As Single)
+        Sub F(ByVal x As Double, ByVal y As Double)
+        Sub F(ByVal x As Decimal, ByVal y As Decimal)
+        Sub F(ByVal x? As Integer, ByVal y? As Integer)
+        Sub F(ByVal x? As UInteger, ByVal y? As UInteger)
+        Sub F(ByVal x? As Long, ByVal y? As Long)
+        Sub F(ByVal x? As ULong, ByVal y? As ULong)
+        Sub F(ByVal x? As Single, ByVal y? As Single)
+        Sub F(ByVal x? As Double, ByVal y? As Double)
+        Sub F(ByVal x? As Decimal, ByVal y? As Decimal)
+    End Interface
+
+    Interface IRelationalSignatures : Inherits IArithmeticSignatures
+        Overloads Sub F(ByVal x As String, ByVal y As String)
+        Overloads Sub F(ByVal x As Char, ByVal y As Char)
+        Overloads Sub F(ByVal x As DateTime, ByVal y As DateTime)
+        Overloads Sub F(ByVal x As TimeSpan, ByVal y As TimeSpan)
+        Overloads Sub F(ByVal x? As Char, ByVal y? As Char)
+        Overloads Sub F(ByVal x? As DateTime, ByVal y? As DateTime)
+        Overloads Sub F(ByVal x? As TimeSpan, ByVal y? As TimeSpan)
+    End Interface
+
+    Interface IEqualitySignatures : Inherits IRelationalSignatures
+        Overloads Sub F(ByVal x As Boolean, ByVal y As Boolean)
+        Overloads Sub F(ByVal x? As Boolean, ByVal y? As Boolean)
+    End Interface
+
+    Interface IAddSignatures : Inherits IArithmeticSignatures
+        Overloads Sub F(ByVal x As DateTime, ByVal y As TimeSpan)
+        Overloads Sub F(ByVal x As TimeSpan, ByVal y As TimeSpan)
+        Overloads Sub F(ByVal x? As DateTime, ByVal y? As TimeSpan)
+        Overloads Sub F(ByVal x? As TimeSpan, ByVal y? As TimeSpan)
+    End Interface
+
+    Interface ISubtractSignatures : Inherits IAddSignatures
+        Overloads Sub F(ByVal x As DateTime, ByVal y As DateTime)
+        Overloads Sub F(ByVal x? As DateTime, ByVal y? As DateTime)
+    End Interface
+
+    Interface INegationSignatures
+        Sub F(ByVal x As Integer)
+        Sub F(ByVal x As Long)
+        Sub F(ByVal x As Single)
+        Sub F(ByVal x As Double)
+        Sub F(ByVal x As Decimal)
+        Sub F(ByVal x As Integer?)
+        Sub F(ByVal x As Long?)
+        Sub F(ByVal x As Single?)
+        Sub F(ByVal x As Double?)
+        Sub F(ByVal x As Decimal?)
+    End Interface
+
+    Interface INotSignatures
+        Sub F(ByVal x As Boolean)
+        Sub F(ByVal x? As Boolean)
+    End Interface
+
+    Interface IEnumerableSignatures
+        Sub Where(ByVal predicate As Boolean)
+        Sub Any()
+        Sub Any(ByVal predicate As Boolean)
+        Sub All(ByVal predicate As Boolean)
+        Sub Count()
+        Sub Count(ByVal predicate As Boolean)
+        Sub Min(ByVal selector As Object)
+        Sub Max(ByVal selector As Object)
+        Sub Sum(ByVal selector As Integer)
+        Sub Sum(ByVal selector? As Integer)
+        Sub Sum(ByVal selector As Long)
+        Sub Sum(ByVal selector? As Long)
+        Sub Sum(ByVal selector As Single)
+        Sub Sum(ByVal selector? As Single)
+        Sub Sum(ByVal selector As Double)
+        Sub Sum(ByVal selector? As Double)
+        Sub Sum(ByVal selector As Decimal)
+        Sub Sum(ByVal selector? As Decimal)
+        Sub Average(ByVal selector As Integer)
+        Sub Average(ByVal selector? As Integer)
+        Sub Average(ByVal selector As Long)
+        Sub Average(ByVal selector? As Long)
+        Sub Average(ByVal selector As Single)
+        Sub Average(ByVal selector? As Single)
+        Sub Average(ByVal selector As Double)
+        Sub Average(ByVal selector? As Double)
+        Sub Average(ByVal selector As Decimal)
+        Sub Average(ByVal selector? As Decimal)
+    End Interface
+
+    Shared ReadOnly predefinedTypes As Type() = { _
+                                                    GetType(Object), _
+                                                    GetType(Boolean), _
+                                                    GetType(Char), _
+                                                    GetType(String), _
+                                                    GetType(SByte), _
+                                                    GetType(Byte), _
+                                                    GetType(Int16), _
+                                                    GetType(UInt16), _
+                                                    GetType(Int32), _
+                                                    GetType(UInt32), _
+                                                    GetType(Int64), _
+                                                    GetType(UInt64), _
+                                                    GetType(Single), _
+                                                    GetType(Double), _
+                                                    GetType(Decimal), _
+                                                    GetType(DateTime), _
+                                                    GetType(TimeSpan), _
+                                                    GetType(Guid), _
+                                                    GetType(Math), _
+                                                    GetType(Convert) _
+                                                }
+
+    Shared ReadOnly trueLiteral As Expression = Expression.Constant(True)
+    Shared ReadOnly falseLiteral As Expression = Expression.Constant(False)
+    Shared ReadOnly nullLiteral As Expression = Expression.Constant(Nothing)
+
+    Shared ReadOnly keywordIt As String = "it"
+    Shared ReadOnly keywordIif As String = "iif"
+    Shared ReadOnly keywordNew As String = "new"
+
+    Shared keywords As Dictionary(Of String, Object)
+
+    Dim symbols As Dictionary(Of String, Object)
+    Dim externals As IDictionary(Of String, Object)
+    Dim literals As Dictionary(Of Expression, String)
+    Dim it As ParameterExpression
+    Dim text As String
+    Dim textPos As Integer
+    Dim textLen As Integer
+    Dim ch As Char
+    Dim tokenVal As Token
+
+    Public Sub New(ByVal parameters As ParameterExpression(), ByVal expression As String, ByVal values As Object())
+        If expression Is Nothing Then Throw New ArgumentNullException("expression")
+        If keywords Is Nothing Then keywords = CreateKeywords()
+        symbols = New Dictionary(Of String, Object)(StringComparer.OrdinalIgnoreCase)
+        literals = New Dictionary(Of Expression, String)()
+        If parameters IsNot Nothing Then ProcessParameters(parameters)
+        If values IsNot Nothing Then ProcessValues(values)
+        text = expression
+        textLen = text.Length
+        SetTextPos(0)
+        NextToken()
+    End Sub
+
+    Sub ProcessParameters(ByVal parameters As ParameterExpression())
+        For Each pe As ParameterExpression In parameters
+            If Not String.IsNullOrEmpty(pe.Name) Then
+                AddSymbol(pe.Name, pe)
+            End If
+        Next
+
+        If (parameters.Length = 1 AndAlso String.IsNullOrEmpty(parameters(0).Name)) Then
+            it = parameters(0)
+        End If
+    End Sub
+
+    Sub ProcessValues(ByVal values As Object())
+        For i As Integer = 0 To values.Length - 1
+            Dim value As Object = values(i)
+            If i = values.Length - 1 AndAlso TryCast(value, IDictionary(Of String, Object)) IsNot Nothing Then
+                externals = DirectCast(value, IDictionary(Of String, Object))
+            Else
+                AddSymbol("@" & i.ToString(System.Globalization.CultureInfo.InvariantCulture), value)
+            End If
+        Next
+    End Sub
+
+    Sub AddSymbol(ByVal name As String, ByVal value As Object)
+        If (symbols.ContainsKey(name)) Then
+            Throw ParseError(Res.DuplicateIdentifier, name)
+        End If
+        symbols.Add(name, value)
+    End Sub
+
+    Public Function Parse(ByVal resultType As Type) As Expression
+        Dim exprPos As Integer = tokenVal.pos
+        Dim expr As Expression = ParseExpression()
+        If resultType IsNot Nothing Then
+            expr = PromoteExpression(expr, resultType, True)
+            If expr Is Nothing Then
+                Throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType))
+            End If
+        End If
+        ValidateToken(TokenId.End, Res.SyntaxError)
+        Return expr
+    End Function
+
+    Public Function ParseOrdering() As IEnumerable(Of DynamicOrdering)
+        Dim orderings As List(Of DynamicOrdering) = New List(Of DynamicOrdering)()
+        Do
+            Dim expr As Expression = ParseExpression()
+            Dim ascending As Boolean = True
+            If TokenIdentifierIs("asc") OrElse TokenIdentifierIs("ascending") Then
+                NextToken()
+            ElseIf TokenIdentifierIs("desc") OrElse TokenIdentifierIs("descending") Then
+                NextToken()
+                ascending = False
+            End If
+            orderings.Add(New DynamicOrdering() With {.Selector = expr, .Ascending = ascending})
+            If tokenVal.id <> TokenId.Comma Then Exit Do
+            NextToken()
+        Loop
+        ValidateToken(TokenId.End, Res.SyntaxError)
+        Return orderings
+    End Function
+    '#pragma warning restore 0219
+
+    ' ?: operator
+    Function ParseExpression() As Expression
+        Dim errorPos As Integer = tokenVal.pos
+        Dim expr As Expression = ParseLogicalOr()
+        If tokenVal.id = TokenId.Question Then
+            NextToken()
+            Dim expr1 As Expression = ParseExpression()
+            ValidateToken(TokenId.Colon, Res.ColonExpected)
+            NextToken()
+            Dim expr2 As Expression = ParseExpression()
+            expr = GenerateConditional(expr, expr1, expr2, errorPos)
+        End If
+        Return expr
+    End Function
+
+    ' ||, or operator
+    Function ParseLogicalOr() As Expression
+        Dim left As Expression = ParseLogicalAnd()
+        Do While tokenVal.id = TokenId.DoubleBar OrElse TokenIdentifierIs("or")
+            Dim op As Token = tokenVal
+            NextToken()
+            Dim right As Expression = ParseLogicalAnd()
+            CheckAndPromoteOperands(GetType(ILogicalSignatures), op.text, left, right, op.pos)
+            left = Expression.OrElse(left, right)
+        Loop
+        Return left
+    End Function
+
+    ' &&, and operator
+    Function ParseLogicalAnd() As Expression
+        Dim left As Expression = ParseComparison()
+        Do While tokenVal.id = TokenId.DoubleAmphersand OrElse TokenIdentifierIs("and")
+            Dim op As Token = tokenVal
+            NextToken()
+            Dim right As Expression = ParseComparison()
+            CheckAndPromoteOperands(GetType(ILogicalSignatures), op.text, left, right, op.pos)
+            left = Expression.AndAlso(left, right)
+        Loop
+        Return left
+    End Function
+
+    ' =, ==, !=, <>, >, >=, <, <= operators
+    Function ParseComparison() As Expression
+        Dim left As Expression = ParseAdditive()
+        Do While tokenVal.id = TokenId.Equal OrElse tokenVal.id = TokenId.DoubleEqual OrElse _
+                 tokenVal.id = TokenId.ExclamationEqual OrElse tokenVal.id = TokenId.LessGreater OrElse _
+                 tokenVal.id = TokenId.GreaterThan OrElse tokenVal.id = TokenId.GreaterThanEqual OrElse _
+                 tokenVal.id = TokenId.LessThan OrElse tokenVal.id = TokenId.LessThanEqual
+            Dim op As Token = tokenVal
+            NextToken()
+            Dim right As Expression = ParseAdditive()
+            Dim isEquality As Boolean = (op.id = TokenId.Equal OrElse op.id = TokenId.DoubleEqual OrElse _
+                                         op.id = TokenId.ExclamationEqual OrElse op.id = TokenId.LessGreater)
+            If isEquality AndAlso Not left.Type.IsValueType AndAlso Not right.Type.IsValueType Then
+                If Not left.Type.Equals(right.Type) Then
+                    If left.Type.IsAssignableFrom(right.Type) Then
+                        right = Expression.Convert(right, left.Type)
+                    ElseIf right.Type.IsAssignableFrom(left.Type) Then
+                        left = Expression.Convert(left, right.Type)
+                    Else
+                        Throw IncompatibleOperandsError(op.text, left, right, op.pos)
+                    End If
+                End If
+            ElseIf IsEnumType(left.Type) OrElse IsEnumType(right.Type) Then
+                If Not left.Type.Equals(right.Type) Then
+                    Dim e As Expression = PromoteExpression(right, left.Type, True)
+                    If e IsNot Nothing Then
+                        right = e
+                    Else
+                        e = PromoteExpression(left, right.Type, True)
+                        If e Is Nothing Then
+                            Throw IncompatibleOperandsError(op.text, left, right, op.pos)
+                        End If
+                        left = e
+                    End If
+                End If
+            Else
+                CheckAndPromoteOperands(If(isEquality, GetType(IEqualitySignatures), GetType(IRelationalSignatures)), _
+                                        op.text, left, right, op.pos)
+            End If
+            Select Case op.id
+                Case TokenId.Equal, TokenId.DoubleEqual
+                    left = GenerateEqual(left, right)
+                Case TokenId.ExclamationEqual, TokenId.LessGreater
+                    left = GenerateNotEqual(left, right)
+                Case TokenId.GreaterThan
+                    left = GenerateGreaterThan(left, right)
+                Case TokenId.GreaterThanEqual
+                    left = GenerateGreaterThanEqual(left, right)
+                Case TokenId.LessThan
+                    left = GenerateLessThan(left, right)
+                Case TokenId.LessThanEqual
+                    left = GenerateLessThanEqual(left, right)
+            End Select
+        Loop
+        Return left
+    End Function
+
+    ' +, -, & operators
+    Function ParseAdditive() As Expression
+        Dim left = ParseMultiplicative()
+        Do While tokenVal.id = TokenId.Plus OrElse tokenVal.id = TokenId.Minus OrElse _
+                 tokenVal.id = TokenId.Amphersand
+            Dim op = tokenVal
+            NextToken()
+            Dim right = ParseMultiplicative()
+            Select Case op.id
+                Case TokenId.Plus
+                    If left.Type.Equals(GetType(String)) OrElse right.Type.Equals(GetType(String)) Then
+                        GoTo amphersand
+                    End If
+                    CheckAndPromoteOperands(GetType(IAddSignatures), op.text, left, right, op.pos)
+                    left = GenerateAdd(left, right)
+                Case TokenId.Minus
+                    CheckAndPromoteOperands(GetType(ISubtractSignatures), op.text, left, right, op.pos)
+                    left = GenerateSubtract(left, right)
+                Case TokenId.Amphersand
+amphersand:
+                    left = GenerateStringConcat(left, right)
+            End Select
+        Loop
+        Return left
+    End Function
+
+    ' *, /, %, mod operators
+    Function ParseMultiplicative() As Expression
+        Dim left = ParseUnary()
+        Do While tokenVal.id = TokenId.Asterisk OrElse tokenVal.id = TokenId.Slash OrElse _
+                 tokenVal.id = TokenId.Percent OrElse TokenIdentifierIs("mod")
+            Dim op = tokenVal
+            NextToken()
+            Dim right = ParseUnary()
+            CheckAndPromoteOperands(GetType(IArithmeticSignatures), op.text, left, right, op.pos)
+            Select Case op.id
+                Case TokenId.Asterisk
+                    left = Expression.Multiply(left, right)
+                Case TokenId.Slash
+                    left = Expression.Divide(left, right)
+                Case TokenId.Percent, TokenId.Identifier
+                    left = Expression.Modulo(left, right)
+            End Select
+        Loop
+        Return left
+    End Function
+
+    ' -, !, not unary operators
+    Function ParseUnary() As Expression
+        If tokenVal.id = TokenId.Minus OrElse tokenVal.id = TokenId.Exclamation OrElse _
+           TokenIdentifierIs("not") Then
+
+            Dim op = tokenVal
+            NextToken()
+            If op.id = TokenId.Minus AndAlso (tokenVal.id = TokenId.IntegerLiteral OrElse _
+                                              tokenVal.id = TokenId.RealLiteral) Then
+                tokenVal.text = "-" & tokenVal.text
+                tokenVal.pos = op.pos
+                Return ParsePrimary()
+            End If
+            Dim expr = ParseUnary()
+            If op.id = TokenId.Minus Then
+                CheckAndPromoteOperand(GetType(INegationSignatures), op.text, expr, op.pos)
+                expr = Expression.Negate(expr)
+            Else
+                CheckAndPromoteOperand(GetType(INotSignatures), op.text, expr, op.pos)
+                expr = Expression.Not(expr)
+            End If
+            Return expr
+        End If
+        Return ParsePrimary()
+    End Function
+
+    Function ParsePrimary() As Expression
+        Dim expr = ParsePrimaryStart()
+        Do
+            If tokenVal.id = TokenId.Dot Then
+                NextToken()
+                expr = ParseMemberAccess(Nothing, expr)
+            ElseIf tokenVal.id = TokenId.OpenBracket Then
+                expr = ParseElementAccess(expr)
+            Else
+                Exit Do
+            End If
+        Loop
+        Return expr
+    End Function
+
+    Function ParsePrimaryStart() As Expression
+        Select Case tokenVal.id
+            Case TokenId.Identifier
+                Return ParseIdentifier()
+            Case TokenId.StringLiteral
+                Return ParseStringLiteral()
+            Case TokenId.IntegerLiteral
+                Return ParseIntegerLiteral()
+            Case TokenId.RealLiteral
+                Return ParseRealLiteral()
+            Case TokenId.OpenParen
+                Return ParseParenExpression()
+            Case Else
+                Throw ParseError(Res.ExpressionExpected)
+        End Select
+    End Function
+
+    Function ParseStringLiteral() As Expression
+        ValidateToken(TokenId.StringLiteral)
+
+        Dim quote = tokenVal.text(0)
+        Dim s = tokenVal.text.Substring(1, tokenVal.text.Length - 2)
+        Dim start = 0
+
+        Do
+            Dim i = s.IndexOf(quote, start)
+            If i < 0 Then Exit Do
+            s = s.Remove(i, 1)
+            start = i + 1
+        Loop
+
+        If quote = "'" Then
+            If s.Length <> 1 Then
+                Throw ParseError(Res.InvalidCharacterLiteral)
+            End If
+            NextToken()
+            Return CreateLiteral(s(0), s)
+        End If
+        NextToken()
+        Return CreateLiteral(s, s)
+    End Function
+
+    Function ParseIntegerLiteral() As Expression
+        ValidateToken(TokenId.IntegerLiteral)
+        Dim text = tokenVal.text
+        If text(0) <> "-" Then
+            Dim value As ULong = 0
+            If Not UInt64.TryParse(text, value) Then
+                Throw ParseError(Res.InvalidIntegerLiteral, text)
+            End If
+
+            NextToken()
+            If value <= CULng(Int32.MaxValue) Then Return CreateLiteral(CInt(value), text)
+            If value <= CULng(UInt32.MaxValue) Then Return CreateLiteral(CUInt(value), text)
+            If value <= CULng(Int64.MaxValue) Then Return CreateLiteral(CLng(value), text)
+            Return CreateLiteral(value, text)
+        Else
+            Dim value As Long = 0
+            If Not Int64.TryParse(text, value) Then
+                Throw ParseError(Res.InvalidIntegerLiteral, text)
+            End If
+            NextToken()
+            If (value >= Int32.MinValue AndAlso value <= Int32.MaxValue) Then
+                Return CreateLiteral(CInt(value), text)
+            End If
+            Return CreateLiteral(value, text)
+        End If
+    End Function
+
+    Function ParseRealLiteral() As Expression
+        ValidateToken(TokenId.RealLiteral)
+        Dim text = tokenVal.text
+        Dim value As Object = Nothing
+        Dim last = text(text.Length - 1)
+        If last = "f" Or last = "F" Then
+            Dim f As Single
+            If Single.TryParse(text.Substring(0, text.Length - 1), f) Then value = f
+
+        Else
+            Dim d As Double
+            If Double.TryParse(text, d) Then value = d
+        End If
+
+        If value Is Nothing Then Throw ParseError(Res.InvalidRealLiteral, text)
+        NextToken()
+        Return CreateLiteral(value, text)
+    End Function
+
+    Function CreateLiteral(ByVal value As Object, ByVal text As String) As Expression
+        Dim expr = Expression.Constant(value)
+        literals.Add(expr, text)
+        Return expr
+    End Function
+
+    Function ParseParenExpression() As Expression
+        ValidateToken(TokenId.OpenParen, Res.OpenParenExpected)
+        NextToken()
+        Dim e = ParseExpression()
+        ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected)
+        NextToken()
+        Return e
+    End Function
+
+    Function ParseIdentifier() As Expression
+        ValidateToken(TokenId.Identifier)
+        Dim value As Object = Nothing
+        If keywords.TryGetValue(tokenVal.text, value) Then
+            If TryCast(value, Type) IsNot Nothing Then Return ParseTypeAccess(DirectCast(value, Type))
+            If value Is keywordIt Then Return ParseIt()
+            If value Is keywordIif Then Return ParseIif()
+            If value Is keywordNew Then Return ParseNew()
+            NextToken()
+            Return DirectCast(value, Expression)
+        End If
+
+        If symbols.TryGetValue(tokenVal.text, value) OrElse _
+           externals IsNot Nothing AndAlso externals.TryGetValue(tokenVal.text, value) Then
+            Dim expr = TryCast(value, Expression)
+            If expr Is Nothing Then
+                expr = Expression.Constant(value)
+            Else
+                Dim lambda = TryCast(expr, LambdaExpression)
+                If lambda IsNot Nothing Then Return ParseLambdaInvocation(lambda)
+            End If
+            NextToken()
+            Return expr
+        End If
+        If it IsNot Nothing Then Return ParseMemberAccess(Nothing, it)
+        Throw ParseError(Res.UnknownIdentifier, tokenVal.text)
+    End Function
+
+    Function ParseIt() As Expression
+        If it Is Nothing Then Throw ParseError(Res.NoItInScope)
+        NextToken()
+        Return it
+    End Function
+
+    Function ParseIif() As Expression
+        Dim errorPos = tokenVal.pos
+        NextToken()
+        Dim args As Expression() = ParseArgumentList()
+        If args.Length <> 3 Then
+            Throw ParseError(errorPos, Res.IifRequiresThreeArgs)
+        End If
+        Return GenerateConditional(args(0), args(1), args(2), errorPos)
+    End Function
+
+    Function GenerateConditional(ByVal test As Expression, ByVal expr1 As Expression, ByVal expr2 As Expression, ByVal errorPos As Integer) As Expression
+        If Not test.Type.Equals(GetType(Boolean)) Then
+            Throw ParseError(errorPos, Res.FirstExprMustBeBool)
+        End If
+        If Not expr1.Type.Equals(expr2.Type) Then
+            Dim expr1as2 As Expression = If(Not expr2.Equals(nullLiteral), PromoteExpression(expr1, expr2.Type, True), Nothing)
+            Dim expr2as1 As Expression = If(Not expr1.Equals(nullLiteral), PromoteExpression(expr2, expr1.Type, True), Nothing)
+            If expr1as2 IsNot Nothing And expr2as1 Is Nothing Then
+                expr1 = expr1as2
+            ElseIf expr2as1 IsNot Nothing And expr1as2 Is Nothing Then
+                expr2 = expr2as1
+            Else
+                Dim type1 = If(Not expr1.Equals(nullLiteral), expr1.Type.Name, "null")
+                Dim type2 = If(Not expr2.Equals(nullLiteral), expr2.Type.Name, "null")
+                If expr1as2 IsNot Nothing And expr2as1 IsNot Nothing Then
+                    Throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2)
+                End If
+                Throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2)
+            End If
+        End If
+        Return Expression.Condition(test, expr1, expr2)
+    End Function
+
+    Function ParseNew() As Expression
+        NextToken()
+        ValidateToken(TokenId.OpenParen, Res.OpenParenExpected)
+        NextToken()
+        Dim properties As New List(Of DynamicProperty)()
+        Dim expressions As New List(Of Expression)()
+        Do
+            Dim exprPos = tokenVal.pos
+            Dim expr = ParseExpression()
+            Dim propName As String
+            If TokenIdentifierIs("as") Then
+                NextToken()
+                propName = GetIdentifier()
+                NextToken()
+            Else
+                Dim [me] As MemberExpression = TryCast(expr, MemberExpression)
+                If [me] Is Nothing Then Throw ParseError(exprPos, Res.MissingAsClause)
+                propName = [me].Member.Name
+            End If
+            expressions.Add(expr)
+            properties.Add(New DynamicProperty(propName, expr.Type))
+            If tokenVal.id <> TokenId.Comma Then Exit Do
+            NextToken()
+        Loop
+        ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected)
+        NextToken()
+        Dim type As Type = DynamicExpression.CreateClass(properties)
+        Dim bindings(properties.Count - 1) As MemberBinding
+        For i As Integer = 0 To bindings.Length - 1
+            bindings(i) = Expression.Bind(type.GetProperty(properties(i).Name), expressions(i))
+        Next
+        Return Expression.MemberInit(Expression.[New](type), bindings)
+    End Function
+
+    Function ParseLambdaInvocation(ByVal lambda As LambdaExpression) As Expression
+        Dim errorPos = tokenVal.pos
+        NextToken()
+        Dim args As Expression() = ParseArgumentList()
+        Dim method As MethodBase = Nothing
+        If FindMethod(lambda.Type, "Invoke", False, args, method) <> 1 Then
+            Throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda)
+        End If
+        Return Expression.Invoke(lambda, args)
+    End Function
+
+    Function ParseTypeAccess(ByVal type As Type) As Expression
+        Dim errorPos = tokenVal.pos
+        NextToken()
+
+        If tokenVal.id = TokenId.Question Then
+            If (Not type.IsValueType) OrElse IsNullableType(type) Then
+                Throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type))
+            End If
+            type = GetType(Nullable(Of Integer)).GetGenericTypeDefinition().MakeGenericType(type)
+            NextToken()
+        End If
+        If tokenVal.id = TokenId.OpenParen Then
+            Dim args As Expression() = ParseArgumentList()
+            Dim method As MethodBase = Nothing
+            Select Case FindBestMethod(type.GetConstructors(), args, method)
+                Case 0
+                    If args.Length = 1 Then
+                        Return GenerateConversion(args(0), type, errorPos)
+                    End If
+                    Throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type))
+                Case 1
+                    Return Expression.[New](DirectCast(method, ConstructorInfo), args)
+                Case Else
+                    Throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type))
+            End Select
+        End If
+        ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected)
+        NextToken()
+        Return ParseMemberAccess(type, Nothing)
+    End Function
+
+    Function GenerateConversion(ByVal expr As Expression, ByVal type As Type, ByVal errorPos As Integer) As Expression
+        Dim exprType = expr.Type
+        If exprType.Equals(type) Then Return expr
+        If exprType.IsValueType AndAlso type.IsValueType Then
+            If (IsNullableType(exprType) OrElse IsNullableType(type)) AndAlso _
+               GetNonNullableType(exprType).Equals(GetNonNullableType(type)) Then
+
+                Return Expression.Convert(expr, type)
+            End If
+            If (IsNumericType(exprType) OrElse IsEnumType(exprType)) AndAlso _
+               (IsNumericType(type) OrElse IsEnumType(type)) Then
+
+                Return Expression.ConvertChecked(expr, type)
+            End If
+        End If
+        If exprType.IsAssignableFrom(type) OrElse type.IsAssignableFrom(exprType) OrElse _
+           exprType.IsInterface OrElse type.IsInterface Then
+            Return Expression.Convert(expr, type)
+        End If
+        Throw ParseError(errorPos, Res.CannotConvertValue, _
+                         GetTypeName(exprType), GetTypeName(type))
+    End Function
+
+
+    Function ParseMemberAccess(ByVal type As Type, ByVal instance As Expression) As Expression
+        If instance IsNot Nothing Then type = instance.Type
+        Dim errorPos = tokenVal.pos
+        Dim id = GetIdentifier()
+        NextToken()
+        If tokenVal.id = TokenId.OpenParen Then
+            If instance IsNot Nothing AndAlso Not type.Equals(GetType(String)) Then
+                Dim enumerableType As Type = FindGenericType(GetType(IEnumerable(Of Object)).GetGenericTypeDefinition(), type)
+                If enumerableType IsNot Nothing Then
+                    Dim elementType As Type = enumerableType.GetGenericArguments()(0)
+                    Return ParseAggregate(instance, elementType, id, errorPos)
+                End If
+            End If
+            Dim args As Expression() = ParseArgumentList()
+            Dim mb As MethodBase = Nothing
+            Select Case FindMethod(type, id, instance Is Nothing, args, mb)
+                Case 0
+                    Throw ParseError(errorPos, Res.NoApplicableMethod, id, GetTypeName(type))
+                Case 1
+                    Dim method = DirectCast(mb, MethodInfo)
+                    If (Not IsPredefinedType(method.DeclaringType)) Then
+                        Throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType))
+                    End If
+                    If method.ReturnType.Equals(GetType(Void)) Then
+                        Throw ParseError(errorPos, Res.MethodIsVoid, id, GetTypeName(method.DeclaringType))
+                    End If
+                    Return Expression.Call(instance, DirectCast(method, MethodInfo), args)
+                Case Else
+                    Throw ParseError(errorPos, Res.AmbiguousMethodInvocation, id, GetTypeName(type))
+            End Select
+        Else
+            Dim member As MemberInfo = FindPropertyOrField(type, id, instance Is Nothing)
+            If member Is Nothing Then
+                Throw ParseError(errorPos, Res.UnknownPropertyOrField, id, GetTypeName(type))
+            End If
+            Return If(TryCast(member, PropertyInfo) IsNot Nothing, _
+                      Expression.Property(instance, DirectCast(member, PropertyInfo)), _
+                      Expression.Field(instance, DirectCast(member, FieldInfo)))
+        End If
+    End Function
+
+    Shared Function FindGenericType(ByVal generic As Type, ByVal type As Type) As Type
+        Do While type IsNot Nothing AndAlso Not type.Equals(GetType(Object))
+            If type.IsGenericType AndAlso type.GetGenericTypeDefinition().Equals(generic) Then Return type
+            If generic.IsInterface Then
+                For Each intfType As Type In type.GetInterfaces()
+                    Dim found As Type = FindGenericType(generic, intfType)
+                    If found IsNot Nothing Then Return found
+                Next
+            End If
+            type = type.BaseType
+        Loop
+        Return Nothing
+    End Function
+
+    Function ParseAggregate(ByVal instance As Expression, ByVal elementType As Type, ByVal methodName As String, ByVal errorPos As Integer) As Expression
+        Dim outerIt As ParameterExpression = it
+        Dim innerIt As ParameterExpression = Expression.Parameter(elementType, "")
+        it = innerIt
+        Dim args As Expression() = ParseArgumentList()
+        it = outerIt
+        Dim signature As MethodBase = Nothing
+        If FindMethod(GetType(IEnumerableSignatures), methodName, False, args, signature) <> 1 Then
+            Throw ParseError(errorPos, Res.NoApplicableAggregate, methodName)
+        End If
+        Dim typeArgs As Type()
+        If signature.Name = "Min" OrElse signature.Name = "Max" Then
+            typeArgs = New Type() {elementType, args(0).Type}
+        Else
+            typeArgs = New Type() {elementType}
+        End If
+
+        If args.Length = 0 Then
+            args = New Expression() {instance}
+        Else
+            args = New Expression() {instance, Expression.Lambda(args(0), innerIt)}
+        End If
+        Return Expression.Call(GetType(Enumerable), signature.Name, typeArgs, args)
+    End Function
+
+    Function ParseArgumentList() As Expression()
+        ValidateToken(TokenId.OpenParen, Res.OpenParenExpected)
+        NextToken()
+        Dim args As Expression() = If(tokenVal.id <> TokenId.CloseParen, ParseArguments(), New Expression(-1) {})
+        ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected)
+        NextToken()
+        Return args
+    End Function
+
+    Function ParseArguments() As Expression()
+        Dim argList As New List(Of Expression)()
+        Do
+            argList.Add(ParseExpression())
+            If tokenVal.id <> TokenId.Comma Then Exit Do
+            NextToken()
+        Loop
+        Return argList.ToArray()
+    End Function
+
+    Function ParseElementAccess(ByVal expr As Expression) As Expression
+        Dim errorPos As Integer = tokenVal.pos
+        ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected)
+        NextToken()
+        Dim args As Expression() = ParseArguments()
+        ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected)
+        NextToken()
+        If expr.Type.IsArray Then
+            If expr.Type.GetArrayRank() <> 1 OrElse args.Length <> 1 Then
+                Throw ParseError(errorPos, Res.CannotIndexMultiDimArray)
+            End If
+            Dim index As Expression = PromoteExpression(args(0), GetType(Integer), True)
+            If index Is Nothing Then
+                Throw ParseError(errorPos, Res.InvalidIndex)
+            End If
+            Return Expression.ArrayIndex(expr, index)
+        Else
+            Dim mb As MethodBase = Nothing
+            Select Case FindIndexer(expr.Type, args, mb)
+                Case 0
+                    Throw ParseError(errorPos, Res.NoApplicableIndexer, GetTypeName(expr.Type))
+                Case 1
+                    Return Expression.Call(expr, DirectCast(mb, MethodInfo), args)
+                Case Else
+                    Throw ParseError(errorPos, Res.AmbiguousIndexerInvocation, GetTypeName(expr.Type))
+            End Select
+        End If
+    End Function
+
+    Shared Function IsPredefinedType(ByVal type As Type) As Boolean
+        For Each t As Type In predefinedTypes
+            If t.Equals(type) Then Return True
+        Next
+
+        Return False
+    End Function
+
+    Shared Function IsNullableType(ByVal type As Type) As Boolean
+        Return type.IsGenericType AndAlso type.GetGenericTypeDefinition().Equals(GetType(Nullable(Of Integer)).GetGenericTypeDefinition())
+    End Function
+
+    Shared Function GetNonNullableType(ByVal type As Type) As Type
+        Return If(IsNullableType(type), type.GetGenericArguments()(0), type)
+    End Function
+
+    Shared Function GetTypeName(ByVal type As Type) As String
+        Dim baseType = GetNonNullableType(type)
+        Dim s = baseType.Name
+        If Not type.Equals(baseType) Then s &= "?"
+        Return s
+    End Function
+
+    Shared Function IsNumericType(ByVal type As Type) As Boolean
+        Return GetNumericTypeKind(type) <> 0
+    End Function
+
+    Shared Function IsSignedIntegralType(ByVal type As Type) As Boolean
+        Return GetNumericTypeKind(type) = 2
+    End Function
+
+    Shared Function IsUnsignedIntegralType(ByVal type As Type) As Boolean
+        Return GetNumericTypeKind(type) = 3
+    End Function
+
+    Shared Function GetNumericTypeKind(ByVal type As Type) As Integer
+        type = GetNonNullableType(type)
+        If type.IsEnum Then Return 0
+        Select Case type.GetTypeCode(type)
+            Case TypeCode.Char, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                Return 1
+            Case TypeCode.SByte, TypeCode.Int16, TypeCode.Int32, TypeCode.Int64
+                Return 2
+            Case TypeCode.Byte, TypeCode.UInt16, TypeCode.UInt32, TypeCode.UInt64
+                Return 3
+            Case Else
+                Return 0
+        End Select
+    End Function
+
+    Shared Function IsEnumType(ByVal type As Type) As Boolean
+        Return GetNonNullableType(type).IsEnum
+    End Function
+
+    Sub CheckAndPromoteOperand(ByVal signatures As Type, ByVal opName As String, ByRef expr As Expression, ByVal errorPos As Integer)
+        Dim args As Expression() = New Expression() {expr}
+        Dim method As MethodBase = Nothing
+        If FindMethod(signatures, "F", False, args, method) <> 1 Then
+            Throw ParseError(errorPos, Res.IncompatibleOperand, opName, GetTypeName(args(0).Type))
+        End If
+        expr = args(0)
+    End Sub
+
+    Sub CheckAndPromoteOperands(ByVal signatures As Type, ByVal opName As String, ByRef left As Expression, ByRef right As Expression, ByVal errorPos As Integer)
+        Dim args As Expression() = New Expression() {left, right}
+        Dim method As MethodBase = Nothing
+        If FindMethod(signatures, "F", False, args, method) <> 1 Then
+            Throw IncompatibleOperandsError(opName, left, right, errorPos)
+        End If
+        left = args(0)
+        right = args(1)
+    End Sub
+
+    Function IncompatibleOperandsError(ByVal opName As String, ByVal left As Expression, ByVal right As Expression, ByVal pos As Integer) As Exception
+        Return ParseError(pos, Res.IncompatibleOperands, opName, GetTypeName(left.Type), GetTypeName(right.Type))
+    End Function
+
+    Function FindPropertyOrField(ByVal type As Type, ByVal memberName As String, ByVal staticAccess As Boolean) As MemberInfo
+        Dim flags As BindingFlags = BindingFlags.Public Or BindingFlags.DeclaredOnly Or _
+                                    If(staticAccess, BindingFlags.Static, BindingFlags.Instance)
+        For Each t As Type In SelfAndBaseTypes(type)
+            Dim members As MemberInfo() = t.FindMembers(MemberTypes.Property Or MemberTypes.Field, _
+                                                        flags, type.FilterNameIgnoreCase, memberName)
+            If members.Length <> 0 Then Return members(0)
+        Next
+        Return Nothing
+    End Function
+
+    Function FindMethod(ByVal type As Type, ByVal methodName As String, ByVal staticAccess As Boolean, ByVal args As Expression(), ByRef method As MethodBase) As Integer
+        Dim flags As BindingFlags = BindingFlags.Public Or BindingFlags.DeclaredOnly Or _
+                                    If(staticAccess, BindingFlags.Static, BindingFlags.Instance)
+        For Each t As Type In SelfAndBaseTypes(type)
+            Dim members As MemberInfo() = t.FindMembers(MemberTypes.Method, _
+                                                        flags, type.FilterNameIgnoreCase, methodName)
+            Dim count As Integer = FindBestMethod(members.Cast(Of MethodBase)(), args, method)
+            If count <> 0 Then Return count
+        Next
+        method = Nothing
+        Return 0
+    End Function
+
+    Function FindIndexer(ByVal type As Type, ByVal args As Expression(), ByRef method As MethodBase) As Integer
+        For Each t As Type In SelfAndBaseTypes(type)
+            Dim members As MemberInfo() = t.GetDefaultMembers()
+            If members.Length <> 0 Then
+                Dim methods As IEnumerable(Of MethodBase) = members. _
+                        OfType(Of PropertyInfo)(). _
+                        Select(Function(p) DirectCast(p.GetGetMethod(), MethodBase)). _
+                        Where(Function(m) m IsNot Nothing)
+                Dim count As Integer = FindBestMethod(methods, args, method)
+                If count <> 0 Then Return count
+            End If
+        Next
+        method = Nothing
+        Return 0
+    End Function
+
+    Shared Function SelfAndBaseTypes(ByVal type As Type) As IEnumerable(Of Type)
+        If type.IsInterface Then
+            Dim types As New List(Of Type)()
+            AddInterface(types, type)
+            Return types
+        End If
+        Return SelfAndBaseClasses(type)
+    End Function
+
+    Shared Function SelfAndBaseClasses(ByVal type As Type) As IEnumerable(Of Type)
+        Dim results As New LinkedList(Of Type)()
+
+        Do While type IsNot Nothing
+            results.AddLast(type)
+            type = type.BaseType
+        Loop
+
+        Return results
+    End Function
+
+    Shared Sub AddInterface(ByVal types As List(Of Type), ByVal type As Type)
+        If Not types.Contains(type) Then
+            types.Add(type)
+        End If
+        For Each t As Type In type.GetInterfaces()
+            AddInterface(types, t)
+        Next
+    End Sub
+
+    Class MethodData
+        Public MethodBase As MethodBase
+        Public Parameters As ParameterInfo()
+        Public Args As Expression()
+    End Class
+
+    Function FindBestMethod(ByVal methods As IEnumerable(Of MethodBase), ByVal args As Expression(), ByRef method As MethodBase) As Integer
+        Dim applicable As MethodData() = methods. _
+                Select(Function(m) New MethodData With {.MethodBase = m, .Parameters = m.GetParameters()}). _
+                Where(Function(m) IsApplicable(m, args)). _
+                ToArray()
+        If applicable.Length > 1 Then
+            applicable = applicable. _
+                Where(Function(m) applicable.All(Function(n) m Is n OrElse IsBetterThan(args, m, n))). _
+                ToArray()
+        End If
+        If applicable.Length = 1 Then
+            Dim md As MethodData = applicable(0)
+            For i As Integer = 0 To args.Length - 1
+                args(i) = md.Args(i)
+            Next
+            method = md.MethodBase
+        Else
+            method = Nothing
+        End If
+        Return applicable.Length
+    End Function
+
+    Function IsApplicable(ByVal method As MethodData, ByVal args As Expression()) As Boolean
+        If method.Parameters.Length <> args.Length Then Return False
+        Dim promotedArgs As Expression() = New Expression(args.Length - 1) {}
+
+        For i As Integer = 0 To args.Length - 1
+            Dim pi As ParameterInfo = method.Parameters(i)
+            If pi.IsOut Then Return False
+            Dim promoted As Expression = PromoteExpression(args(i), pi.ParameterType, False)
+            If promoted Is Nothing Then Return False
+            promotedArgs(i) = promoted
+        Next i
+        method.Args = promotedArgs
+
+        Return True
+    End Function
+
+    Function PromoteExpression(ByVal expr As Expression, ByVal type As Type, ByVal exact As Boolean) As Expression
+        If expr.Type.Equals(type) Then Return expr
+        If TryCast(expr, ConstantExpression) IsNot Nothing Then
+            Dim ce = DirectCast(expr, ConstantExpression)
+            If ce.Equals(nullLiteral) Then
+                If Not type.IsValueType OrElse IsNullableType(type) Then
+                    Return Expression.Constant(Nothing, type)
+                End If
+            Else
+                Dim text As String = Nothing
+                If literals.TryGetValue(ce, text) Then
+                    Dim target As Type = GetNonNullableType(type)
+                    Dim value As Object = Nothing
+                    Select Case type.GetTypeCode(ce.Type)
+                        Case TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64
+                            value = ParseNumber(text, target)
+                        Case TypeCode.Double
+                            If target.Equals(GetType(Decimal)) Then value = ParseNumber(text, target)
+                        Case TypeCode.String
+                            value = ParseEnum(text, target)
+                    End Select
+                    If value IsNot Nothing Then Return Expression.Constant(value, type)
+                End If
+            End If
+        End If
+
+        If IsCompatibleWith(expr.Type, type) Then
+            If type.IsValueType OrElse exact Then Return Expression.Convert(expr, type)
+            Return expr
+        End If
+        Return Nothing
+    End Function
+
+    Shared Function ParseNumber(ByVal text As String, ByVal type As Type) As Object
+        Select Case type.GetTypeCode(GetNonNullableType(type))
+            Case TypeCode.SByte
+                Dim sb As SByte
+                If SByte.TryParse(text, sb) Then Return sb
+            Case TypeCode.Byte
+                Dim b As Byte
+                If Byte.TryParse(text, b) Then Return b
+            Case TypeCode.Int16
+                Dim s As Short
+                If Short.TryParse(text, s) Then Return s
+            Case TypeCode.UInt16
+                Dim us As UShort
+                If UShort.TryParse(text, us) Then Return us
+            Case TypeCode.Int32
+                Dim i As Integer
+                If Integer.TryParse(text, i) Then Return i
+            Case TypeCode.UInt32
+                Dim ui As UInteger
+                If UInteger.TryParse(text, ui) Then Return ui
+            Case TypeCode.Int64
+                Dim l As Long
+                If Long.TryParse(text, l) Then Return l
+            Case TypeCode.UInt64
+                Dim ul As ULong
+                If ULong.TryParse(text, ul) Then Return ul
+            Case TypeCode.Single
+                Dim f As Single
+                If Single.TryParse(text, f) Then Return f
+            Case TypeCode.Double
+                Dim d As Double
+                If Double.TryParse(text, d) Then Return d
+            Case TypeCode.Decimal
+                Dim e As Decimal
+                If Decimal.TryParse(text, e) Then Return e
+        End Select
+        Return Nothing
+    End Function
+
+    Shared Function ParseEnum(ByVal name As String, ByVal type As Type) As Object
+        If type.IsEnum Then
+            Dim memberInfos As MemberInfo() = type.FindMembers(MemberTypes.Field, _
+                                                               BindingFlags.Public Or BindingFlags.DeclaredOnly Or BindingFlags.Static, _
+                                                               type.FilterNameIgnoreCase, name)
+            If memberInfos.Length <> 0 Then Return DirectCast(memberInfos(0), FieldInfo).GetValue(Nothing)
+        End If
+        Return Nothing
+    End Function
+
+    Shared Function IsCompatibleWith(ByVal source As Type, ByVal target As Type) As Boolean
+        If source.Equals(target) Then Return True
+        If Not target.IsValueType Then Return target.IsAssignableFrom(source)
+        Dim st As Type = GetNonNullableType(source)
+        Dim tt As Type = GetNonNullableType(target)
+        If Not st.Equals(source) AndAlso tt.Equals(target) Then Return False
+        Dim sc As TypeCode = If(st.IsEnum, TypeCode.Object, System.Type.GetTypeCode(st))
+        Dim tc As TypeCode = If(tt.IsEnum, TypeCode.Object, System.Type.GetTypeCode(tt))
+
+        Select Case sc
+            Case TypeCode.SByte
+                Select Case tc
+                    Case TypeCode.SByte, TypeCode.Int16, TypeCode.Int32, TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.Byte
+                Select Case tc
+                    Case TypeCode.Byte, TypeCode.Int16, TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.Int16
+                Select Case tc
+                    Case TypeCode.Int16, TypeCode.Int32, TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.UInt16
+                Select Case tc
+                    Case TypeCode.UInt16, TypeCode.Int32, TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.Int32
+                Select Case tc
+                    Case TypeCode.Int32, TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.UInt32
+                Select Case tc
+                    Case TypeCode.UInt32, TypeCode.Int64, TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.Int64
+                Select Case tc
+                    Case TypeCode.Int64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.UInt64
+                Select Case tc
+                    Case TypeCode.UInt64, TypeCode.Single, TypeCode.Double, TypeCode.Decimal
+                        Return True
+                End Select
+            Case TypeCode.Single
+                Select Case tc
+                    Case TypeCode.Single, TypeCode.Double
+                        Return True
+                End Select
+            Case Else
+                If st.Equals(tt) Then Return True
+        End Select
+        Return False
+    End Function
+
+    Shared Function IsBetterThan(ByVal args As Expression(), ByVal m1 As MethodData, ByVal m2 As MethodData) As Boolean
+        Dim better = False
+        For i As Integer = 0 To args.Length - 1
+            Dim c As Integer = CompareConversions(args(i).Type, _
+                                                  m1.Parameters(i).ParameterType, _
+                                                  m2.Parameters(i).ParameterType)
+            If c < 0 Then Return False
+            If c > 0 Then better = True
+        Next i
+        Return better
+    End Function
+
+    ' Return 1 if s -> t1 is a better conversion than s -> t2
+    ' Return -1 if s -> t2 is a better conversion than s -> t1
+    ' Return 0 if neither conversion is better
+    Shared Function CompareConversions(ByVal s As Type, ByVal t1 As Type, ByVal t2 As Type) As Integer
+        If t1.Equals(t2) Then Return 0
+        If s.Equals(t1) Then Return 1
+        If s.Equals(t2) Then Return -1
+        Dim t1t2 As Boolean = IsCompatibleWith(t1, t2)
+        Dim t2t1 As Boolean = IsCompatibleWith(t2, t1)
+        If t1t2 AndAlso Not t2t1 Then Return 1
+        If t2t1 AndAlso Not t1t2 Then Return -1
+        If IsSignedIntegralType(t1) AndAlso IsUnsignedIntegralType(t2) Then Return 1
+        If IsSignedIntegralType(t2) AndAlso IsUnsignedIntegralType(t1) Then Return -1
+        Return 0
+    End Function
+
+    Function GenerateEqual(ByVal left As Expression, ByVal right As Expression) As Expression
+        Return Expression.Equal(left, right)
+    End Function
+
+    Function GenerateNotEqual(ByVal left As Expression, ByVal right As Expression) As Expression
+        Return Expression.NotEqual(left, right)
+    End Function
+
+    Function GenerateGreaterThan(ByVal left As Expression, ByVal right As Expression) As Expression
+        If left.Type.Equals(GetType(String)) Then
+            Return Expression.GreaterThan( _
+                                          GenerateStaticMethodCall("Compare", left, right), _
+                                          Expression.Constant(0))
+        End If
+        Return Expression.GreaterThan(left, right)
+    End Function
+
+    Function GenerateGreaterThanEqual(ByVal left As Expression, ByVal right As Expression) As Expression
+        If left.Type.Equals(GetType(String)) Then
+            Return Expression.GreaterThanOrEqual( _
+                                                 GenerateStaticMethodCall("Compare", left, right), _
+                                                 Expression.Constant(0))
+        End If
+        Return Expression.GreaterThanOrEqual(left, right)
+    End Function
+
+    Function GenerateLessThan(ByVal left As Expression, ByVal right As Expression) As Expression
+        If left.Type.Equals(GetType(String)) Then
+            Return Expression.LessThan( _
+                                       GenerateStaticMethodCall("Compare", left, right), _
+                                       Expression.Constant(0))
+        End If
+        Return Expression.LessThan(left, right)
+    End Function
+
+    Function GenerateLessThanEqual(ByVal left As Expression, ByVal right As Expression) As Expression
+        If left.Type.Equals(GetType(String)) Then
+            Return Expression.LessThanOrEqual( _
+                                              GenerateStaticMethodCall("Compare", left, right), _
+                                              Expression.Constant(0))
+        End If
+        Return Expression.LessThanOrEqual(left, right)
+    End Function
+
+    Function GenerateAdd(ByVal left As Expression, ByVal right As Expression) As Expression
+        If left.Type.Equals(GetType(String)) AndAlso right.Type.Equals(GetType(String)) Then
+            Return GenerateStaticMethodCall("Concat", left, right)
+        End If
+        Return Expression.Add(left, right)
+    End Function
+
+    Function GenerateSubtract(ByVal left As Expression, ByVal right As expression) As Expression
+        Return Expression.Subtract(left, right)
+    End Function
+
+    Function GenerateStringConcat(ByVal left As Expression, ByVal right As Expression) As Expression
+        Return Expression.Call( _
+                               Nothing, _
+                               GetType(String).GetMethod("Concat", New Type() {GetType(Object), GetType(Object)}), _
+                               New Expression() {left, right})
+    End Function
+
+    Function GetStaticMethod(ByVal methodName As String, ByVal left As expression, ByVal right As expression) As MethodInfo
+        Return left.Type.GetMethod(methodName, New Type() {left.Type, right.Type})
+    End Function
+
+    Function GenerateStaticMethodCall(ByVal methodName As String, ByVal left As Expression, ByVal right As Expression) As Expression
+        Return Expression.Call(Nothing, GetStaticMethod(methodName, left, right), New Expression() {left, right})
+    End Function
+
+    Sub SetTextPos(ByVal pos As Integer)
+        textPos = pos
+        ch = If(textPos < textLen, text(textPos), ChrW(0))
+    End Sub
+
+    Sub NextChar()
+        If textPos < textLen Then textPos += 1
+        ch = If(textPos < textLen, text(textPos), ChrW(0))
+    End Sub
+
+    Sub NextToken()
+        Do While Char.IsWhiteSpace(ch)
+            NextChar()
+        Loop
+
+        Dim t As TokenId
+        Dim tokenPos = textPos
+        Select Case ch
+            Case "!"c
+                NextChar()
+                If ch = "=" Then
+                    NextChar()
+                    t = TokenId.ExclamationEqual
+                Else
+                    t = TokenId.Exclamation
+                End If
+            Case "%"c
+                NextChar()
+                t = TokenId.Percent
+            Case "&"c
+                NextChar()
+                If ch = "&" Then
+                    NextChar()
+                    t = TokenId.DoubleAmphersand
+                Else
+                    t = TokenId.Amphersand
+                End If
+            Case "("c
+                NextChar()
+                t = TokenId.OpenParen
+            Case ")"c
+                NextChar()
+                t = TokenId.CloseParen
+            Case "*"c
+                NextChar()
+                t = TokenId.Asterisk
+            Case "+"c
+                NextChar()
+                t = TokenId.Plus
+            Case ","c
+                NextChar()
+                t = TokenId.Comma
+            Case "-"c
+                NextChar()
+                t = TokenId.Minus
+            Case "."c
+                NextChar()
+                t = TokenId.Dot
+            Case "/"c
+                NextChar()
+                t = TokenId.Slash
+            Case ":"c
+                NextChar()
+                t = TokenId.Colon
+            Case "<"c
+                NextChar()
+                If ch = "=" Then
+                    NextChar()
+                    t = TokenId.LessThanEqual
+                ElseIf ch = ">" Then
+                    NextChar()
+                    t = TokenId.LessGreater
+                Else
+                    t = TokenId.LessThan
+                End If
+            Case "="c
+                NextChar()
+                If ch = "=" Then
+                    NextChar()
+                    t = TokenId.DoubleEqual
+                Else
+                    t = TokenId.Equal
+                End If
+            Case ">"c
+                NextChar()
+                If ch = "=" Then
+                    NextChar()
+                    t = TokenId.GreaterThanEqual
+                Else
+                    t = TokenId.GreaterThan
+                End If
+            Case "?"c
+                NextChar()
+                t = TokenId.Question
+            Case "["c
+                NextChar()
+                t = TokenId.OpenBracket
+            Case "]"c
+                NextChar()
+                t = TokenId.CloseBracket
+            Case "|"c
+                NextChar()
+                If ch = "|" Then
+                    NextChar()
+                    t = TokenId.DoubleBar
+                Else
+                    t = TokenId.Bar
+                End If
+            Case "'"c, """"c
+                Dim quote = ch
+                Do
+                    NextChar()
+                    Do While textPos < textLen AndAlso ch <> quote
+                        NextChar()
+                    Loop
+                    If textPos = textLen Then Throw ParseError(textPos, Res.UnterminatedStringLiteral)
+                    NextChar()
+                Loop While ch = quote
+                t = TokenId.StringLiteral
+            Case Else
+                If Char.IsLetter(ch) OrElse ch = "@" OrElse ch = "_" Then
+                    Do
+                        NextChar()
+                    Loop While Char.IsLetterOrDigit(ch) OrElse ch = "_"
+                    t = TokenId.Identifier
+                    Exit Select
+                End If
+
+                If Char.IsDigit(ch) Then
+                    t = TokenId.IntegerLiteral
+                    Do
+                        NextChar()
+                    Loop While Char.IsDigit(ch)
+                    If ch = "." Then
+                        t = TokenId.RealLiteral
+                        NextChar()
+                        ValidateDigit()
+                        Do
+                            NextChar()
+                        Loop While Char.IsDigit(ch)
+                    End If
+                    If ch = "E" OrElse ch = "e" Then
+                        t = TokenId.RealLiteral
+                        NextChar()
+                        If ch = "+" OrElse ch = "-" Then NextChar()
+                        ValidateDigit()
+                        Do
+                            NextChar()
+                        Loop While Char.IsDigit(ch)
+                    End If
+                    If ch = "F" Or ch = "f" Then NextChar()
+                    Exit Select
+                End If
+                If textPos = textLen Then
+                    t = TokenId.End
+                    Exit Select
+                End If
+                Throw ParseError(textPos, Res.InvalidCharacter, ch)
+        End Select
+        tokenVal.id = t
+        tokenVal.text = text.Substring(tokenPos, textPos - tokenPos)
+        tokenVal.pos = tokenPos
+    End Sub
+
+    Function TokenIdentifierIs(ByVal id As String) As Boolean
+        Return tokenVal.id = TokenId.Identifier AndAlso String.Equals(id, tokenVal.text, StringComparison.OrdinalIgnoreCase)
+    End Function
+
+    Function GetIdentifier() As String
+        ValidateToken(TokenId.Identifier, Res.IdentifierExpected)
+        Dim id = tokenVal.text
+        If id.Length > 1 AndAlso id(0) = "@" Then id = id.Substring(1)
+        Return id
+    End Function
+
+    Sub ValidateDigit()
+        If Not Char.IsDigit(ch) Then Throw ParseError(textPos, Res.DigitExpected)
+    End Sub
+
+    Sub ValidateToken(ByVal t As TokenId, ByVal errorMessage As String)
+        If tokenVal.id <> t Then Throw ParseError(errorMessage)
+    End Sub
+
+    Sub ValidateToken(ByVal t As TokenId)
+        If tokenVal.id <> t Then Throw ParseError(Res.SyntaxError)
+    End Sub
+
+    Overloads Function ParseError(ByVal format As String, ByVal ParamArray args As Object()) As Exception
+        Return ParseError(tokenVal.pos, format, args)
+    End Function
+
+    Overloads Function ParseError(ByVal pos As Integer, ByVal format As String, ByVal ParamArray args As Object()) As Exception
+        Return New ParseException(String.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos)
+    End Function
+
+    Shared Function CreateKeywords() As Dictionary(Of String, Object)
+        Dim d As New Dictionary(Of String, Object)(StringComparer.OrdinalIgnoreCase)
+
+        d.Add("true", trueLiteral)
+        d.Add("false", falseLiteral)
+        d.Add("null", nullLiteral)
+        d.Add(keywordIt, keywordIt)
+        d.Add(keywordIif, keywordIif)
+        d.Add(keywordNew, keywordNew)
+
+        For Each type As Type In predefinedTypes
+            d.Add(type.Name, type)
+        Next
+
+        Return d
+    End Function
+End Class
+
+Class Res
+    Public Const DuplicateIdentifier As String = "The identifier '{0}' was defined more than once"
+    Public Const ExpressionTypeMismatch As String = "Expression of type '{0}' expected"
+    Public Const ExpressionExpected As String = "Expression expected"
+    Public Const InvalidCharacterLiteral As String = "Character literal must contain exactly one character"
+    Public Const InvalidIntegerLiteral As String = "Invalid integer literal '{0}'"
+    Public Const InvalidRealLiteral As String = "Invalid real literal '{0}'"
+    Public Const UnknownIdentifier As String = "Unknown identifier '{0}'"
+    Public Const NoItInScope As String = "No 'it' is in scope"
+    Public Const IifRequiresThreeArgs As String = "The 'iif' function requires three arguments"
+    Public Const FirstExprMustBeBool As String = "The first expression must be of type 'Boolean'"
+    Public Const BothTypesConvertToOther As String = "Both of the types '{0}' and '{1}' convert to the other"
+    Public Const NeitherTypeConvertsToOther As String = "Neither of the types '{0}' and '{1}' converts to the other"
+    Public Const MissingAsClause As String = "Expression is missing an 'as' clause"
+    Public Const ArgsIncompatibleWithLambda As String = "Argument list incompatible with lambda expression"
+    Public Const TypeHasNoNullableForm As String = "Type '{0}' has no nullable form"
+    Public Const NoMatchingConstructor As String = "No matching constructor in type '{0}'"
+    Public Const AmbiguousConstructorInvocation As String = "Ambiguous invocation of '{0}' constructor"
+    Public Const CannotConvertValue As String = "A value of type '{0}' cannot be converted to type '{1}'"
+    Public Const NoApplicableMethod As String = "No applicable method '{0}' exists in type '{1}'"
+    Public Const MethodsAreInaccessible As String = "Methods on type '{0}' are not accessible"
+    Public Const MethodIsVoid As String = "Method '{0}' in type '{1}' does not return a value"
+    Public Const AmbiguousMethodInvocation As String = "Ambiguous invocation of method '{0}' in type '{1}'"
+    Public Const UnknownPropertyOrField As String = "No property or field '{0}' exists in type '{1}'"
+    Public Const NoApplicableAggregate As String = "No applicable aggregate method '{0}' exists"
+    Public Const CannotIndexMultiDimArray As String = "Indexing of multi-dimensional arrays is not supported"
+    Public Const InvalidIndex As String = "Array index must be an integer expression"
+    Public Const NoApplicableIndexer As String = "No applicable indexer exists in type '{0}'"
+    Public Const AmbiguousIndexerInvocation As String = "Ambiguous invocation of indexer in type '{0}'"
+    Public Const IncompatibleOperand As String = "Operator '{0}' incompatible with operand type '{1}'"
+    Public Const IncompatibleOperands As String = "Operator '{0}' incompatible with operand types '{1}' and '{2}'"
+    Public Const UnterminatedStringLiteral As String = "Unterminated string literal"
+    Public Const InvalidCharacter As String = "Syntax error '{0}'"
+    Public Const DigitExpected As String = "Digit expected"
+    Public Const SyntaxError As String = "Syntax error"
+    Public Const TokenExpected As String = "{0} expected"
+    Public Const ParseExceptionFormat As String = "{0} (at index {1})"
+    Public Const ColonExpected As String = "':' expected"
+    Public Const OpenParenExpected As String = "'(' expected"
+    Public Const CloseParenOrOperatorExpected As String = "')' or operator expected"
+    Public Const CloseParenOrCommaExpected As String = "')' or ',' expected"
+    Public Const DotOrOpenParenExpected As String = "'.' or '(' expected"
+    Public Const OpenBracketExpected As String = "'[' expected"
+    Public Const CloseBracketOrCommaExpected As String = "']' or ',' expected"
+    Public Const IdentifierExpected As String = "Identifier expected"
+End Class
\ No newline at end of file

Modified: branches/query/Tween/StatusDictionary.vb
===================================================================
--- branches/query/Tween/StatusDictionary.vb	2011-01-05 17:35:54 UTC (rev 1321)
+++ branches/query/Tween/StatusDictionary.vb	2011-01-05 23:31:47 UTC (rev 1322)
@@ -23,10 +23,13 @@
 
 Imports System.Collections.Generic
 Imports System.Collections.ObjectModel
+Imports System.Linq.Expressions
 Imports Tween.TweenCustomControl
 Imports System.Text.RegularExpressions
 Imports System.Web.HttpUtility
 Imports System.Text
+Imports System.Linq
+Imports System.Linq.Expressions.DynamicExpression
 
 Public NotInheritable Class PostClass
     Implements ICloneable
@@ -2001,6 +2004,8 @@
     Private _exSource As String = ""
     Private _moveFrom As Boolean = False
     Private _setMark As Boolean = True
+    Private _useLambda As Boolean = False
+    Private _exuseLambda As Boolean = False
 
     Public Sub New()
 
@@ -2044,6 +2049,9 @@
             If _isRt Then
                 fs.Append("RT/")
             End If
+            If _useLambda Then
+                fs.Append("LambdaExp/")
+            End If
             If Not String.IsNullOrEmpty(_source) Then
                 fs.AppendFormat("Src…{0}/", _source)
             End If
@@ -2087,6 +2095,9 @@
             If _isExRt Then
                 fs.Append("RT/")
             End If
+            If _exuseLambda Then
+                fs.Append("LambdaExp/")
+            End If
             If Not String.IsNullOrEmpty(_exSource) Then
                 fs.AppendFormat("Src…{0}/", _exSource)
             End If
@@ -2245,6 +2256,24 @@
         End Set
     End Property
 
+    Public Property UseLambda() As Boolean
+        Get
+            Return _useLambda
+        End Get
+        Set(ByVal value As Boolean)
+            _useLambda = value
+        End Set
+    End Property
+
+    Public Property ExUseLambda() As Boolean
+        Get
+            Return _exuseLambda
+        End Get
+        Set(ByVal value As Boolean)
+            _exuseLambda = value
+        End Set
+    End Property
+
     Public Property UseRegex() As Boolean
         Get
             Return _useRegex
@@ -2303,6 +2332,14 @@
         Return MakeSummary()
     End Function
 
+    Public Function ExecuteLambdaExpression(ByVal expr As String, ByVal post As PostClass) As Boolean
+        Dim dlg As [Delegate]
+        Dim exp As LambdaExpression
+        exp = ParseLambda(Of PostClass, Boolean)(expr, post)
+        dlg = exp.Compile()
+        Return DirectCast(dlg.DynamicInvoke(post), Boolean)
+    End Function
+
     Public Function IsHit(ByVal post As PostClass) As HITRESULT
         Dim bHit As Boolean = True
         Dim tBody As String
@@ -2339,6 +2376,8 @@
                 For Each fs As String In _body
                     If _useRegex Then
                         If Not Regex.IsMatch(tBody, fs, rgOpt) Then bHit = False
+                    ElseIf _useLambda Then
+                        If Not ExecuteLambdaExpression(fs, post) Then bHit = False
                     Else
                         If _caseSensitive Then
                             If Not tBody.Contains(fs) Then bHit = False
@@ -2357,6 +2396,8 @@
                     If Not (Regex.IsMatch(post.Name, fs, rgOpt) OrElse
                             (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) OrElse
                             Regex.IsMatch(tBody, fs, rgOpt)) Then bHit = False
+                ElseIf _useLambda Then
+                    If Not ExecuteLambdaExpression(fs, post) Then bHit = False
                 Else
                     If _caseSensitive Then
                         If Not (post.Name.Contains(fs) OrElse _
@@ -2416,6 +2457,8 @@
                             For Each fs As String In _exbody
                                 If _exuseRegex Then
                                     If Regex.IsMatch(tBody, fs, rgOpt) Then exFlag = True
+                                ElseIf _exuseLambda Then
+                                    If ExecuteLambdaExpression(fs, post) Then exFlag = True
                                 Else
                                     If _excaseSensitive Then
                                         If tBody.Contains(fs) Then exFlag = True
@@ -2435,6 +2478,8 @@
                             If Regex.IsMatch(post.Name, fs, rgOpt) OrElse
                                (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) OrElse
                                Regex.IsMatch(tBody, fs, rgOpt) Then exFlag = True
+                        ElseIf _exuseLambda Then
+                            If ExecuteLambdaExpression(fs, post) Then exFlag = True
                         Else
                             If _excaseSensitive Then
                                 If post.Name.Contains(fs) OrElse _

Modified: branches/query/Tween/Tween.vbproj
===================================================================
--- branches/query/Tween/Tween.vbproj	2011-01-05 17:35:54 UTC (rev 1321)
+++ branches/query/Tween/Tween.vbproj	2011-01-05 23:31:47 UTC (rev 1322)
@@ -142,6 +142,7 @@
     <Compile Include="DetailsListView.vb">
       <SubType>Component</SubType>
     </Compile>
+    <Compile Include="Dynamic.vb" />
     <Compile Include="EventViewerDialog.Designer.vb">
       <DependentUpon>EventViewerDialog.vb</DependentUpon>
     </Compile>

Modified: branches/query/Tween.sln
===================================================================
--- branches/query/Tween.sln	2011-01-05 17:35:54 UTC (rev 1321)
+++ branches/query/Tween.sln	2011-01-05 23:31:47 UTC (rev 1322)
@@ -1,6 +1,6 @@
 
 Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Basic Express 2010
+# Visual Studio 2010
 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Tween", "Tween\Tween.vbproj", "{41B54F21-5442-47D4-80F0-872D56D9E1FD}"
 EndProject
 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TweenUp", "TweenUp\TweenUp.vbproj", "{EF3CD31B-6669-4932-A0E0-1EA44E4BCE89}"
@@ -13,8 +13,8 @@
 		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|Any CPU.Build.0 = Debug|x86
 		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|x86.ActiveCfg = Debug|x86
 		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Debug|x86.Build.0 = Debug|x86
 		{41B54F21-5442-47D4-80F0-872D56D9E1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU



Tween-svn メーリングリストの案内
Back to archive index