Linq表达式树解析2

来源:互联网 发布:动漫神作推荐知乎 编辑:程序博客网 时间:2024/05/19 15:21

接着上一篇:Linq表达式树解析1

demohttp://pan.baidu.com/s/1hqmWxt6

核心代码是老外的,如下:

//Copyright (C) Microsoft Corporation.  All rights reserved.using System;using System.Collections.Generic;using System.Text;using System.Linq;using System.Linq.Expressions;using System.Reflection;using System.Reflection.Emit;using System.Threading;namespace System.Linq.Dynamic{    public static class DynamicQueryable    {        public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)        {            return (IQueryable<T>)Where((IQueryable)source, predicate, values);        }        public static IQueryable Where(this IQueryable source, string predicate, params object[] values)        {            if (source == null) throw new ArgumentNullException("source");            if (predicate == null) throw new ArgumentNullException("predicate");            LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);            return source.Provider.CreateQuery(                Expression.Call(                    typeof(Queryable), "Where",                    new Type[] { source.ElementType },                    source.Expression, Expression.Quote(lambda)));        }        public static IQueryable Select(this IQueryable source, string selector, params object[] values)        {            if (source == null) throw new ArgumentNullException("source");            if (selector == null) throw new ArgumentNullException("selector");            LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);            return source.Provider.CreateQuery(                Expression.Call(                    typeof(Queryable), "Select",                    new Type[] { source.ElementType, lambda.Body.Type },                    source.Expression, Expression.Quote(lambda)));        }        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)        {            return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);        }        public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)        {            if (source == null) throw new ArgumentNullException("source");            if (ordering == null) throw new ArgumentNullException("ordering");            ParameterExpression[] parameters = new ParameterExpression[] {                Expression.Parameter(source.ElementType, "") };            ExpressionParser parser = new ExpressionParser(parameters, ordering, values);            IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();            Expression queryExpr = source.Expression;            string methodAsc = "OrderBy";            string methodDesc = "OrderByDescending";            foreach (DynamicOrdering o in orderings)            {                queryExpr = Expression.Call(                    typeof(Queryable), o.Ascending ? methodAsc : methodDesc,                    new Type[] { source.ElementType, o.Selector.Type },                    queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));                methodAsc = "ThenBy";                methodDesc = "ThenByDescending";            }            return source.Provider.CreateQuery(queryExpr);        }        public static IQueryable Take(this IQueryable source, int count)        {            if (source == null) throw new ArgumentNullException("source");            return source.Provider.CreateQuery(                Expression.Call(                    typeof(Queryable), "Take",                    new Type[] { source.ElementType },                    source.Expression, Expression.Constant(count)));        }        public static IQueryable Skip(this IQueryable source, int count)        {            if (source == null) throw new ArgumentNullException("source");            return source.Provider.CreateQuery(                Expression.Call(                    typeof(Queryable), "Skip",                    new Type[] { source.ElementType },                    source.Expression, Expression.Constant(count)));        }        public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)        {            if (source == null) throw new ArgumentNullException("source");            if (keySelector == null) throw new ArgumentNullException("keySelector");            if (elementSelector == null) throw new ArgumentNullException("elementSelector");            LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);            LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);            return source.Provider.CreateQuery(                Expression.Call(                    typeof(Queryable), "GroupBy",                    new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },                    source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));        }        public static bool Any(this IQueryable source)        {            if (source == null) throw new ArgumentNullException("source");            return (bool)source.Provider.Execute(                Expression.Call(                    typeof(Queryable), "Any",                    new Type[] { source.ElementType }, source.Expression));        }        public static int Count(this IQueryable source)        {            if (source == null) throw new ArgumentNullException("source");            return (int)source.Provider.Execute(                Expression.Call(                    typeof(Queryable), "Count",                    new Type[] { source.ElementType }, source.Expression));        }    }    public abstract class DynamicClass    {        public override string ToString()        {            PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);            StringBuilder sb = new StringBuilder();            sb.Append("{");            for (int i = 0; i < props.Length; i++)            {                if (i > 0) sb.Append(", ");                sb.Append(props[i].Name);                sb.Append("=");                sb.Append(props[i].GetValue(this, null));            }            sb.Append("}");            return sb.ToString();        }    }    public class DynamicProperty    {        string name;        Type type;        public DynamicProperty(string name, Type type)        {            if (name == null) throw new ArgumentNullException("name");            if (type == null) throw new ArgumentNullException("type");            this.name = name;            this.type = type;        }        public string Name        {            get { return name; }        }        public Type Type        {            get { return type; }        }    }    public static class DynamicExpression    {        public static Expression Parse(Type resultType, string expression, params object[] values)        {            ExpressionParser parser = new ExpressionParser(null, expression, values);            return parser.Parse(resultType);        }        public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)        {            return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values);        }        public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)        {            ExpressionParser parser = new ExpressionParser(parameters, expression, values);            return Expression.Lambda(parser.Parse(resultType), parameters);        }        public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)        {            return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);        }        public static Type CreateClass(params DynamicProperty[] properties)        {            return ClassFactory.Instance.GetDynamicClass(properties);        }        public static Type CreateClass(IEnumerable<DynamicProperty> properties)        {            return ClassFactory.Instance.GetDynamicClass(properties);        }    }    internal class DynamicOrdering    {        public Expression Selector;        public bool Ascending;    }    internal class Signature : IEquatable<Signature>    {        public DynamicProperty[] properties;        public int hashCode;        public Signature(IEnumerable<DynamicProperty> properties)        {            this.properties = properties.ToArray();            hashCode = 0;            foreach (DynamicProperty p in properties)            {                hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();            }        }        public override int GetHashCode()        {            return hashCode;        }        public override bool Equals(object obj)        {            return obj is Signature ? Equals((Signature)obj) : false;        }        public bool Equals(Signature other)        {            if (properties.Length != other.properties.Length) return false;            for (int i = 0; i < properties.Length; i++)            {                if (properties[i].Name != other.properties[i].Name ||                    properties[i].Type != other.properties[i].Type) return false;            }            return true;        }    }    internal class ClassFactory    {        public static readonly ClassFactory Instance = new ClassFactory();        static ClassFactory() { }  // Trigger lazy initialization of static fields        ModuleBuilder module;        Dictionary<Signature, Type> classes;        int classCount;        ReaderWriterLock rwLock;        private ClassFactory()        {            AssemblyName name = new AssemblyName("DynamicClasses");            AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);#if ENABLE_LINQ_PARTIAL_TRUST            new ReflectionPermission(PermissionState.Unrestricted).Assert();#endif            try            {                module = assembly.DefineDynamicModule("Module");            }            finally            {#if ENABLE_LINQ_PARTIAL_TRUST                PermissionSet.RevertAssert();#endif            }            classes = new Dictionary<Signature, Type>();            rwLock = new ReaderWriterLock();        }        public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)        {            rwLock.AcquireReaderLock(Timeout.Infinite);            try            {                Signature signature = new Signature(properties);                Type type;                if (!classes.TryGetValue(signature, out type))                {                    type = CreateDynamicClass(signature.properties);                    classes.Add(signature, type);                }                return type;            }            finally            {                rwLock.ReleaseReaderLock();            }        }        Type CreateDynamicClass(DynamicProperty[] properties)        {            LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);            try            {                string typeName = "DynamicClass" + (classCount + 1);#if ENABLE_LINQ_PARTIAL_TRUST                new ReflectionPermission(PermissionState.Unrestricted).Assert();#endif                try                {                    TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |                        TypeAttributes.Public, typeof(DynamicClass));                    FieldInfo[] fields = GenerateProperties(tb, properties);                    GenerateEquals(tb, fields);                    GenerateGetHashCode(tb, fields);                    Type result = tb.CreateType();                    classCount++;                    return result;                }                finally                {#if ENABLE_LINQ_PARTIAL_TRUST                    PermissionSet.RevertAssert();#endif                }            }            finally            {                rwLock.DowngradeFromWriterLock(ref cookie);            }        }        FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)        {            FieldInfo[] fields = new FieldBuilder[properties.Length];            for (int i = 0; i < properties.Length; i++)            {                DynamicProperty dp = properties[i];                FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);                PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);                MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,                    MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,                    dp.Type, Type.EmptyTypes);                ILGenerator genGet = mbGet.GetILGenerator();                genGet.Emit(OpCodes.Ldarg_0);                genGet.Emit(OpCodes.Ldfld, fb);                genGet.Emit(OpCodes.Ret);                MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,                    MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,                    null, new Type[] { dp.Type });                ILGenerator genSet = 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;            }            return fields;        }        void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)        {            MethodBuilder mb = tb.DefineMethod("Equals",                MethodAttributes.Public | MethodAttributes.ReuseSlot |                MethodAttributes.Virtual | MethodAttributes.HideBySig,                typeof(bool), new Type[] { typeof(object) });            ILGenerator gen = mb.GetILGenerator();            LocalBuilder other = gen.DeclareLocal(tb);            Label next = 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);            foreach (FieldInfo field in fields)            {                Type ft = field.FieldType;                Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);                next = gen.DefineLabel();                gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);                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 }), null);                gen.Emit(OpCodes.Brtrue_S, next);                gen.Emit(OpCodes.Ldc_I4_0);                gen.Emit(OpCodes.Ret);                gen.MarkLabel(next);            }            gen.Emit(OpCodes.Ldc_I4_1);            gen.Emit(OpCodes.Ret);        }        void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)        {            MethodBuilder mb = tb.DefineMethod("GetHashCode",                MethodAttributes.Public | MethodAttributes.ReuseSlot |                MethodAttributes.Virtual | MethodAttributes.HideBySig,                typeof(int), Type.EmptyTypes);            ILGenerator gen = mb.GetILGenerator();            gen.Emit(OpCodes.Ldc_I4_0);            foreach (FieldInfo field in fields)            {                Type ft = field.FieldType;                Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);                gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);                gen.Emit(OpCodes.Ldarg_0);                gen.Emit(OpCodes.Ldfld, field);                gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);                gen.Emit(OpCodes.Xor);            }            gen.Emit(OpCodes.Ret);        }    }    public sealed class ParseException : Exception    {        int position;        public ParseException(string message, int position)            : base(message)        {            this.position = position;        }        public int Position        {            get { return position; }        }        public override string ToString()        {            return string.Format(Res.ParseExceptionFormat, Message, position);        }    }    internal class ExpressionParser    {        struct Token        {            public TokenId id;            public string text;            public int pos;        }        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        }        interface ILogicalSignatures        {            void F(bool x, bool y);            void F(bool? x, bool? y);        }        interface IArithmeticSignatures        {            void F(int x, int y);            void F(uint x, uint y);            void F(long x, long y);            void F(ulong x, ulong y);            void F(float x, float y);            void F(double x, double y);            void F(decimal x, decimal y);            void F(int? x, int? y);            void F(uint? x, uint? y);            void F(long? x, long? y);            void F(ulong? x, ulong? y);            void F(float? x, float? y);            void F(double? x, double? y);            void F(decimal? x, decimal? y);        }        interface IRelationalSignatures : IArithmeticSignatures        {            void F(string x, string y);            void F(char x, char y);            void F(DateTime x, DateTime y);            void F(TimeSpan x, TimeSpan y);            void F(char? x, char? y);            void F(DateTime? x, DateTime? y);            void F(TimeSpan? x, TimeSpan? y);        }        interface IEqualitySignatures : IRelationalSignatures        {            void F(bool x, bool y);            void F(bool? x, bool? y);        }        interface IAddSignatures : IArithmeticSignatures        {            void F(DateTime x, TimeSpan y);            void F(TimeSpan x, TimeSpan y);            void F(DateTime? x, TimeSpan? y);            void F(TimeSpan? x, TimeSpan? y);        }        interface ISubtractSignatures : IAddSignatures        {            void F(DateTime x, DateTime y);            void F(DateTime? x, DateTime? y);        }        interface INegationSignatures        {            void F(int x);            void F(long x);            void F(float x);            void F(double x);            void F(decimal x);            void F(int? x);            void F(long? x);            void F(float? x);            void F(double? x);            void F(decimal? x);        }        interface INotSignatures        {            void F(bool x);            void F(bool? x);        }        interface IEnumerableSignatures        {            void Where(bool predicate);            void Any();            void Any(bool predicate);            void All(bool predicate);            void Count();            void Count(bool predicate);            void Min(object selector);            void Max(object selector);            void Sum(int selector);            void Sum(int? selector);            void Sum(long selector);            void Sum(long? selector);            void Sum(float selector);            void Sum(float? selector);            void Sum(double selector);            void Sum(double? selector);            void Sum(decimal selector);            void Sum(decimal? selector);            void Average(int selector);            void Average(int? selector);            void Average(long selector);            void Average(long? selector);            void Average(float selector);            void Average(float? selector);            void Average(double selector);            void Average(double? selector);            void Average(decimal selector);            void Average(decimal? selector);        }        static readonly Type[] predefinedTypes = {            typeof(Object),            typeof(Boolean),            typeof(Char),            typeof(String),            typeof(SByte),            typeof(Byte),            typeof(Int16),            typeof(UInt16),            typeof(Int32),            typeof(UInt32),            typeof(Int64),            typeof(UInt64),            typeof(Single),            typeof(Double),            typeof(Decimal),            typeof(DateTime),            typeof(TimeSpan),            typeof(Guid),            typeof(Math),            typeof(Convert)        };        static readonly Expression trueLiteral = Expression.Constant(true);        static readonly Expression falseLiteral = Expression.Constant(false);        static readonly Expression nullLiteral = Expression.Constant(null);        static readonly string keywordIt = "it";        static readonly string keywordIif = "iif";        static readonly string keywordNew = "new";        static Dictionary<string, object> keywords;        Dictionary<string, object> symbols;        IDictionary<string, object> externals;        Dictionary<Expression, string> literals;        ParameterExpression it;        string text;        int textPos;        int textLen;        char ch;        Token token;        public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)        {            if (expression == null) throw new ArgumentNullException("expression");            if (keywords == null) keywords = CreateKeywords();            symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);            literals = new Dictionary<Expression, string>();            if (parameters != null) ProcessParameters(parameters);            if (values != null) ProcessValues(values);            text = expression;            textLen = text.Length;            SetTextPos(0);            NextToken();        }        void ProcessParameters(ParameterExpression[] parameters)        {            foreach (ParameterExpression pe in parameters)                if (!String.IsNullOrEmpty(pe.Name))                    AddSymbol(pe.Name, pe);            if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))                it = parameters[0];        }        void ProcessValues(object[] values)        {            for (int i = 0; i < values.Length; i++)            {                object value = values[i];                if (i == values.Length - 1 && value is IDictionary<string, object>)                {                    externals = (IDictionary<string, object>)value;                }                else                {                    AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);                }            }        }        void AddSymbol(string name, object value)        {            if (symbols.ContainsKey(name))                throw ParseError(Res.DuplicateIdentifier, name);            symbols.Add(name, value);        }        public Expression Parse(Type resultType)        {            int exprPos = token.pos;            Expression expr = ParseExpression();            if (resultType != null)                if ((expr = PromoteExpression(expr, resultType, true)) == null)                    throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));            ValidateToken(TokenId.End, Res.SyntaxError);            return expr;        }#pragma warning disable 0219        public IEnumerable<DynamicOrdering> ParseOrdering()        {            List<DynamicOrdering> orderings = new List<DynamicOrdering>();            while (true)            {                Expression expr = ParseExpression();                bool ascending = true;                if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))                {                    NextToken();                }                else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))                {                    NextToken();                    ascending = false;                }                orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });                if (token.id != TokenId.Comma) break;                NextToken();            }            ValidateToken(TokenId.End, Res.SyntaxError);            return orderings;        }#pragma warning restore 0219        // ?: operator        Expression ParseExpression()        {            int errorPos = token.pos;            Expression expr = ParseLogicalOr();            if (token.id == TokenId.Question)            {                NextToken();                Expression expr1 = ParseExpression();                ValidateToken(TokenId.Colon, Res.ColonExpected);                NextToken();                Expression expr2 = ParseExpression();                expr = GenerateConditional(expr, expr1, expr2, errorPos);            }            return expr;        }        // ||, or operator        Expression ParseLogicalOr()        {            Expression left = ParseLogicalAnd();            while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))            {                Token op = token;                NextToken();                Expression right = ParseLogicalAnd();                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);                left = Expression.OrElse(left, right);            }            return left;        }        // &&, and operator        Expression ParseLogicalAnd()        {            Expression left = ParseComparison();            while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))            {                Token op = token;                NextToken();                Expression right = ParseComparison();                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);                left = Expression.AndAlso(left, right);            }            return left;        }        // =, ==, !=, <>, >, >=, <, <= operators        Expression ParseComparison()        {            Expression left = ParseAdditive();            while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||                token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||                token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||                token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual)            {                Token op = token;                NextToken();                Expression right = ParseAdditive();                bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||                    op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;                if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)                {                    if (left.Type != right.Type)                    {                        if (left.Type.IsAssignableFrom(right.Type))                        {                            right = Expression.Convert(right, left.Type);                        }                        else if (right.Type.IsAssignableFrom(left.Type))                        {                            left = Expression.Convert(left, right.Type);                        }                        else                        {                            throw IncompatibleOperandsError(op.text, left, right, op.pos);                        }                    }                }                else if (IsEnumType(left.Type) || IsEnumType(right.Type))                {                    if (left.Type != right.Type)                    {                        Expression e;                        if ((e = PromoteExpression(right, left.Type, true)) != null)                        {                            right = e;                        }                        else if ((e = PromoteExpression(left, right.Type, true)) != null)                        {                            left = e;                        }                        else                        {                            throw IncompatibleOperandsError(op.text, left, right, op.pos);                        }                    }                }                else                {                    CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),                        op.text, ref left, ref right, op.pos);                }                switch (op.id)                {                    case TokenId.Equal:                    case TokenId.DoubleEqual:                        left = GenerateEqual(left, right);                        break;                    case TokenId.ExclamationEqual:                    case TokenId.LessGreater:                        left = GenerateNotEqual(left, right);                        break;                    case TokenId.GreaterThan:                        left = GenerateGreaterThan(left, right);                        break;                    case TokenId.GreaterThanEqual:                        left = GenerateGreaterThanEqual(left, right);                        break;                    case TokenId.LessThan:                        left = GenerateLessThan(left, right);                        break;                    case TokenId.LessThanEqual:                        left = GenerateLessThanEqual(left, right);                        break;                }            }            return left;        }        // +, -, & operators        Expression ParseAdditive()        {            Expression left = ParseMultiplicative();            while (token.id == TokenId.Plus || token.id == TokenId.Minus ||                token.id == TokenId.Amphersand)            {                Token op = token;                NextToken();                Expression right = ParseMultiplicative();                switch (op.id)                {                    case TokenId.Plus:                        if (left.Type == typeof(string) || right.Type == typeof(string))                            goto case TokenId.Amphersand;                        CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos);                        left = GenerateAdd(left, right);                        break;                    case TokenId.Minus:                        CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos);                        left = GenerateSubtract(left, right);                        break;                    case TokenId.Amphersand:                        left = GenerateStringConcat(left, right);                        break;                }            }            return left;        }        // *, /, %, mod operators        Expression ParseMultiplicative()        {            Expression left = ParseUnary();            while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||                token.id == TokenId.Percent || TokenIdentifierIs("mod"))            {                Token op = token;                NextToken();                Expression right = ParseUnary();                CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos);                switch (op.id)                {                    case TokenId.Asterisk:                        left = Expression.Multiply(left, right);                        break;                    case TokenId.Slash:                        left = Expression.Divide(left, right);                        break;                    case TokenId.Percent:                    case TokenId.Identifier:                        left = Expression.Modulo(left, right);                        break;                }            }            return left;        }        // -, !, not unary operators        Expression ParseUnary()        {            if (token.id == TokenId.Minus || token.id == TokenId.Exclamation ||                TokenIdentifierIs("not"))            {                Token op = token;                NextToken();                if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral ||                    token.id == TokenId.RealLiteral))                {                    token.text = "-" + token.text;                    token.pos = op.pos;                    return ParsePrimary();                }                Expression expr = ParseUnary();                if (op.id == TokenId.Minus)                {                    CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos);                    expr = Expression.Negate(expr);                }                else                {                    CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos);                    expr = Expression.Not(expr);                }                return expr;            }            return ParsePrimary();        }        Expression ParsePrimary()        {            Expression expr = ParsePrimaryStart();            while (true)            {                if (token.id == TokenId.Dot)                {                    NextToken();                    expr = ParseMemberAccess(null, expr);                }                else if (token.id == TokenId.OpenBracket)                {                    expr = ParseElementAccess(expr);                }                else                {                    break;                }            }            return expr;        }        Expression ParsePrimaryStart()        {            switch (token.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();                default:                    throw ParseError(Res.ExpressionExpected);            }        }        Expression ParseStringLiteral()        {            ValidateToken(TokenId.StringLiteral);            char quote = token.text[0];            string s = token.text.Substring(1, token.text.Length - 2);            int start = 0;            while (true)            {                int i = s.IndexOf(quote, start);                if (i < 0) break;                s = s.Remove(i, 1);                start = i + 1;            }            if (quote == '\'')            {                if (s.Length != 1)                    throw ParseError(Res.InvalidCharacterLiteral);                NextToken();                return CreateLiteral(s[0], s);            }            NextToken();            return CreateLiteral(s, s);        }        Expression ParseIntegerLiteral()        {            ValidateToken(TokenId.IntegerLiteral);            string text = token.text;            if (text[0] != '-')            {                ulong value;                if (!UInt64.TryParse(text, out value))                    throw ParseError(Res.InvalidIntegerLiteral, text);                NextToken();                if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text);                if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text);                if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text);                return CreateLiteral(value, text);            }            else            {                long value;                if (!Int64.TryParse(text, out value))                    throw ParseError(Res.InvalidIntegerLiteral, text);                NextToken();                if (value >= Int32.MinValue && value <= Int32.MaxValue)                    return CreateLiteral((int)value, text);                return CreateLiteral(value, text);            }        }        Expression ParseRealLiteral()        {            ValidateToken(TokenId.RealLiteral);            string text = token.text;            object value = null;            char last = text[text.Length - 1];            if (last == 'F' || last == 'f')            {                float f;                if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f;            }            else            {                double d;                if (Double.TryParse(text, out d)) value = d;            }            if (value == null) throw ParseError(Res.InvalidRealLiteral, text);            NextToken();            return CreateLiteral(value, text);        }        Expression CreateLiteral(object value, string text)        {            ConstantExpression expr = Expression.Constant(value);            literals.Add(expr, text);            return expr;        }        Expression ParseParenExpression()        {            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);            NextToken();            Expression e = ParseExpression();            ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);            NextToken();            return e;        }        Expression ParseIdentifier()        {            ValidateToken(TokenId.Identifier);            object value;            if (keywords.TryGetValue(token.text, out value))            {                if (value is Type) return ParseTypeAccess((Type)value);                if (value == (object)keywordIt) return ParseIt();                if (value == (object)keywordIif) return ParseIif();                if (value == (object)keywordNew) return ParseNew();                NextToken();                return (Expression)value;            }            if (symbols.TryGetValue(token.text, out value) ||                externals != null && externals.TryGetValue(token.text, out value))            {                Expression expr = value as Expression;                if (expr == null)                {                    expr = Expression.Constant(value);                }                else                {                    LambdaExpression lambda = expr as LambdaExpression;                    if (lambda != null) return ParseLambdaInvocation(lambda);                }                NextToken();                return expr;            }            if (it != null) return ParseMemberAccess(null, it);            throw ParseError(Res.UnknownIdentifier, token.text);        }        Expression ParseIt()        {            if (it == null)                throw ParseError(Res.NoItInScope);            NextToken();            return it;        }        Expression ParseIif()        {            int errorPos = token.pos;            NextToken();            Expression[] args = ParseArgumentList();            if (args.Length != 3)                throw ParseError(errorPos, Res.IifRequiresThreeArgs);            return GenerateConditional(args[0], args[1], args[2], errorPos);        }        Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)        {            if (test.Type != typeof(bool))                throw ParseError(errorPos, Res.FirstExprMustBeBool);            if (expr1.Type != expr2.Type)            {                Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;                Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;                if (expr1as2 != null && expr2as1 == null)                {                    expr1 = expr1as2;                }                else if (expr2as1 != null && expr1as2 == null)                {                    expr2 = expr2as1;                }                else                {                    string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";                    string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";                    if (expr1as2 != null && expr2as1 != null)                        throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2);                    throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2);                }            }            return Expression.Condition(test, expr1, expr2);        }        Expression ParseNew()        {            NextToken();            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);            NextToken();            List<DynamicProperty> properties = new List<DynamicProperty>();            List<Expression> expressions = new List<Expression>();            while (true)            {                int exprPos = token.pos;                Expression expr = ParseExpression();                string propName;                if (TokenIdentifierIs("as"))                {                    NextToken();                    propName = GetIdentifier();                    NextToken();                }                else                {                    MemberExpression me = expr as MemberExpression;                    if (me == null) throw ParseError(exprPos, Res.MissingAsClause);                    propName = me.Member.Name;                }                expressions.Add(expr);                properties.Add(new DynamicProperty(propName, expr.Type));                if (token.id != TokenId.Comma) break;                NextToken();            }            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);            NextToken();            Type type = DynamicExpression.CreateClass(properties);            MemberBinding[] bindings = new MemberBinding[properties.Count];            for (int i = 0; i < bindings.Length; i++)                bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);            return Expression.MemberInit(Expression.New(type), bindings);        }        Expression ParseLambdaInvocation(LambdaExpression lambda)        {            int errorPos = token.pos;            NextToken();            Expression[] args = ParseArgumentList();            MethodBase method;            if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1)                throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda);            return Expression.Invoke(lambda, args);        }        Expression ParseTypeAccess(Type type)        {            int errorPos = token.pos;            NextToken();            if (token.id == TokenId.Question)            {                if (!type.IsValueType || IsNullableType(type))                    throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type));                type = typeof(Nullable<>).MakeGenericType(type);                NextToken();            }            if (token.id == TokenId.OpenParen)            {                Expression[] args = ParseArgumentList();                MethodBase method;                switch (FindBestMethod(type.GetConstructors(), args, out method))                {                    case 0:                        if (args.Length == 1)                            return GenerateConversion(args[0], type, errorPos);                        throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));                    case 1:                        return Expression.New((ConstructorInfo)method, args);                    default:                        throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));                }            }            ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);            NextToken();            return ParseMemberAccess(type, null);        }        Expression GenerateConversion(Expression expr, Type type, int errorPos)        {            Type exprType = expr.Type;            if (exprType == type) return expr;            if (exprType.IsValueType && type.IsValueType)            {                if ((IsNullableType(exprType) || IsNullableType(type)) &&                    GetNonNullableType(exprType) == GetNonNullableType(type))                    return Expression.Convert(expr, type);                if ((IsNumericType(exprType) || IsEnumType(exprType)) &&                    (IsNumericType(type)) || IsEnumType(type))                    return Expression.ConvertChecked(expr, type);            }            if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||                exprType.IsInterface || type.IsInterface)                return Expression.Convert(expr, type);            throw ParseError(errorPos, Res.CannotConvertValue,                GetTypeName(exprType), GetTypeName(type));        }        Expression ParseMemberAccess(Type type, Expression instance)        {            if (instance != null) type = instance.Type;            int errorPos = token.pos;            string id = GetIdentifier();            NextToken();            if (token.id == TokenId.OpenParen)            {                if (instance != null && type != typeof(string))                {                    Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);                    if (enumerableType != null)                    {                        Type elementType = enumerableType.GetGenericArguments()[0];                        return ParseAggregate(instance, elementType, id, errorPos);                    }                }                Expression[] args = ParseArgumentList();                MethodBase mb;                switch (FindMethod(type, id, instance == null, args, out mb))                {                    case 0:                        throw ParseError(errorPos, Res.NoApplicableMethod,                            id, GetTypeName(type));                    case 1:                        MethodInfo method = (MethodInfo)mb;                        if (!IsPredefinedType(method.DeclaringType))                            throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));                        if (method.ReturnType == typeof(void))                            throw ParseError(errorPos, Res.MethodIsVoid,                                id, GetTypeName(method.DeclaringType));                        return Expression.Call(instance, (MethodInfo)method, args);                    default:                        throw ParseError(errorPos, Res.AmbiguousMethodInvocation,                            id, GetTypeName(type));                }            }            else            {                MemberInfo member = FindPropertyOrField(type, id, instance == null);                if (member == null)                    throw ParseError(errorPos, Res.UnknownPropertyOrField,                        id, GetTypeName(type));                return member is PropertyInfo ?                    Expression.Property(instance, (PropertyInfo)member) :                    Expression.Field(instance, (FieldInfo)member);            }        }        static Type FindGenericType(Type generic, Type type)        {            while (type != null && type != typeof(object))            {                if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type;                if (generic.IsInterface)                {                    foreach (Type intfType in type.GetInterfaces())                    {                        Type found = FindGenericType(generic, intfType);                        if (found != null) return found;                    }                }                type = type.BaseType;            }            return null;        }        Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)        {            ParameterExpression outerIt = it;            ParameterExpression innerIt = Expression.Parameter(elementType, "");            it = innerIt;            Expression[] args = ParseArgumentList();            it = outerIt;            MethodBase signature;            if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)                throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);            Type[] typeArgs;            if (signature.Name == "Min" || signature.Name == "Max")            {                typeArgs = new Type[] { elementType, args[0].Type };            }            else            {                typeArgs = new Type[] { elementType };            }            if (args.Length == 0)            {                args = new Expression[] { instance };            }            else            {                args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) };            }            return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);        }        Expression[] ParseArgumentList()        {            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);            NextToken();            Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[0];            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);            NextToken();            return args;        }        Expression[] ParseArguments()        {            List<Expression> argList = new List<Expression>();            while (true)            {                argList.Add(ParseExpression());                if (token.id != TokenId.Comma) break;                NextToken();            }            return argList.ToArray();        }        Expression ParseElementAccess(Expression expr)        {            int errorPos = token.pos;            ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);            NextToken();            Expression[] args = ParseArguments();            ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);            NextToken();            if (expr.Type.IsArray)            {                if (expr.Type.GetArrayRank() != 1 || args.Length != 1)                    throw ParseError(errorPos, Res.CannotIndexMultiDimArray);                Expression index = PromoteExpression(args[0], typeof(int), true);                if (index == null)                    throw ParseError(errorPos, Res.InvalidIndex);                return Expression.ArrayIndex(expr, index);            }            else            {                MethodBase mb;                switch (FindIndexer(expr.Type, args, out mb))                {                    case 0:                        throw ParseError(errorPos, Res.NoApplicableIndexer,                            GetTypeName(expr.Type));                    case 1:                        return Expression.Call(expr, (MethodInfo)mb, args);                    default:                        throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,                            GetTypeName(expr.Type));                }            }        }        static bool IsPredefinedType(Type type)        {            foreach (Type t in predefinedTypes) if (t == type) return true;            return false;        }        static bool IsNullableType(Type type)        {            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);        }        static Type GetNonNullableType(Type type)        {            return IsNullableType(type) ? type.GetGenericArguments()[0] : type;        }        static string GetTypeName(Type type)        {            Type baseType = GetNonNullableType(type);            string s = baseType.Name;            if (type != baseType) s += '?';            return s;        }        static bool IsNumericType(Type type)        {            return GetNumericTypeKind(type) != 0;        }        static bool IsSignedIntegralType(Type type)        {            return GetNumericTypeKind(type) == 2;        }        static bool IsUnsignedIntegralType(Type type)        {            return GetNumericTypeKind(type) == 3;        }        static int GetNumericTypeKind(Type type)        {            type = GetNonNullableType(type);            if (type.IsEnum) return 0;            switch (Type.GetTypeCode(type))            {                case TypeCode.Char:                case TypeCode.Single:                case TypeCode.Double:                case TypeCode.Decimal:                    return 1;                case TypeCode.SByte:                case TypeCode.Int16:                case TypeCode.Int32:                case TypeCode.Int64:                    return 2;                case TypeCode.Byte:                case TypeCode.UInt16:                case TypeCode.UInt32:                case TypeCode.UInt64:                    return 3;                default:                    return 0;            }        }        static bool IsEnumType(Type type)        {            return GetNonNullableType(type).IsEnum;        }        void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)        {            Expression[] args = new Expression[] { expr };            MethodBase method;            if (FindMethod(signatures, "F", false, args, out method) != 1)                throw ParseError(errorPos, Res.IncompatibleOperand,                    opName, GetTypeName(args[0].Type));            expr = args[0];        }        void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)        {            Expression[] args = new Expression[] { left, right };            MethodBase method;            if (FindMethod(signatures, "F", false, args, out method) != 1)                throw IncompatibleOperandsError(opName, left, right, errorPos);            left = args[0];            right = args[1];        }        Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)        {            return ParseError(pos, Res.IncompatibleOperands,                opName, GetTypeName(left.Type), GetTypeName(right.Type));        }        MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)        {            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |                (staticAccess ? BindingFlags.Static : BindingFlags.Instance);            foreach (Type t in SelfAndBaseTypes(type))            {                MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,                    flags, Type.FilterNameIgnoreCase, memberName);                if (members.Length != 0) return members[0];            }            return null;        }        int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)        {            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |                (staticAccess ? BindingFlags.Static : BindingFlags.Instance);            foreach (Type t in SelfAndBaseTypes(type))            {                MemberInfo[] members = t.FindMembers(MemberTypes.Method,                    flags, Type.FilterNameIgnoreCase, methodName);                int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);                if (count != 0) return count;            }            method = null;            return 0;        }        int FindIndexer(Type type, Expression[] args, out MethodBase method)        {            foreach (Type t in SelfAndBaseTypes(type))            {                MemberInfo[] members = t.GetDefaultMembers();                if (members.Length != 0)                {                    IEnumerable<MethodBase> methods = members.                        OfType<PropertyInfo>().                        Select(p => (MethodBase)p.GetGetMethod()).                        Where(m => m != null);                    int count = FindBestMethod(methods, args, out method);                    if (count != 0) return count;                }            }            method = null;            return 0;        }        static IEnumerable<Type> SelfAndBaseTypes(Type type)        {            if (type.IsInterface)            {                List<Type> types = new List<Type>();                AddInterface(types, type);                return types;            }            return SelfAndBaseClasses(type);        }        static IEnumerable<Type> SelfAndBaseClasses(Type type)        {            while (type != null)            {                yield return type;                type = type.BaseType;            }        }        static void AddInterface(List<Type> types, Type type)        {            if (!types.Contains(type))            {                types.Add(type);                foreach (Type t in type.GetInterfaces()) AddInterface(types, t);            }        }        class MethodData        {            public MethodBase MethodBase;            public ParameterInfo[] Parameters;            public Expression[] Args;        }        int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)        {            MethodData[] applicable = methods.                Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).                Where(m => IsApplicable(m, args)).                ToArray();            if (applicable.Length > 1)            {                applicable = applicable.                    Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).                    ToArray();            }            if (applicable.Length == 1)            {                MethodData md = applicable[0];                for (int i = 0; i < args.Length; i++) args[i] = md.Args[i];                method = md.MethodBase;            }            else            {                method = null;            }            return applicable.Length;        }        bool IsApplicable(MethodData method, Expression[] args)        {            if (method.Parameters.Length != args.Length) return false;            Expression[] promotedArgs = new Expression[args.Length];            for (int i = 0; i < args.Length; i++)            {                ParameterInfo pi = method.Parameters[i];                if (pi.IsOut) return false;                Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);                if (promoted == null) return false;                promotedArgs[i] = promoted;            }            method.Args = promotedArgs;            return true;        }        Expression PromoteExpression(Expression expr, Type type, bool exact)        {            if (expr.Type == type) return expr;            if (expr is ConstantExpression)            {                ConstantExpression ce = (ConstantExpression)expr;                if (ce == nullLiteral)                {                    if (!type.IsValueType || IsNullableType(type))                        return Expression.Constant(null, type);                }                else                {                    string text;                    if (literals.TryGetValue(ce, out text))                    {                        Type target = GetNonNullableType(type);                        Object value = null;                        switch (Type.GetTypeCode(ce.Type))                        {                            case TypeCode.Int32:                            case TypeCode.UInt32:                            case TypeCode.Int64:                            case TypeCode.UInt64:                                value = ParseNumber(text, target);                                break;                            case TypeCode.Double:                                if (target == typeof(decimal)) value = ParseNumber(text, target);                                break;                            case TypeCode.String:                                value = ParseEnum(text, target);                                break;                        }                        if (value != null)                            return Expression.Constant(value, type);                    }                }            }            if (IsCompatibleWith(expr.Type, type))            {                if (type.IsValueType || exact) return Expression.Convert(expr, type);                return expr;            }            return null;        }        static object ParseNumber(string text, Type type)        {            switch (Type.GetTypeCode(GetNonNullableType(type)))            {                case TypeCode.SByte:                    sbyte sb;                    if (sbyte.TryParse(text, out sb)) return sb;                    break;                case TypeCode.Byte:                    byte b;                    if (byte.TryParse(text, out b)) return b;                    break;                case TypeCode.Int16:                    short s;                    if (short.TryParse(text, out s)) return s;                    break;                case TypeCode.UInt16:                    ushort us;                    if (ushort.TryParse(text, out us)) return us;                    break;                case TypeCode.Int32:                    int i;                    if (int.TryParse(text, out i)) return i;                    break;                case TypeCode.UInt32:                    uint ui;                    if (uint.TryParse(text, out ui)) return ui;                    break;                case TypeCode.Int64:                    long l;                    if (long.TryParse(text, out l)) return l;                    break;                case TypeCode.UInt64:                    ulong ul;                    if (ulong.TryParse(text, out ul)) return ul;                    break;                case TypeCode.Single:                    float f;                    if (float.TryParse(text, out f)) return f;                    break;                case TypeCode.Double:                    double d;                    if (double.TryParse(text, out d)) return d;                    break;                case TypeCode.Decimal:                    decimal e;                    if (decimal.TryParse(text, out e)) return e;                    break;            }            return null;        }        static object ParseEnum(string name, Type type)        {            if (type.IsEnum)            {                MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,                    BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,                    Type.FilterNameIgnoreCase, name);                if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null);            }            return null;        }        static bool IsCompatibleWith(Type source, Type target)        {            if (source == target) return true;            if (!target.IsValueType) return target.IsAssignableFrom(source);            Type st = GetNonNullableType(source);            Type tt = GetNonNullableType(target);            if (st != source && tt == target) return false;            TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);            TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);            switch (sc)            {                case TypeCode.SByte:                    switch (tc)                    {                        case TypeCode.SByte:                        case TypeCode.Int16:                        case TypeCode.Int32:                        case TypeCode.Int64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.Byte:                    switch (tc)                    {                        case TypeCode.Byte:                        case TypeCode.Int16:                        case TypeCode.UInt16:                        case TypeCode.Int32:                        case TypeCode.UInt32:                        case TypeCode.Int64:                        case TypeCode.UInt64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.Int16:                    switch (tc)                    {                        case TypeCode.Int16:                        case TypeCode.Int32:                        case TypeCode.Int64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.UInt16:                    switch (tc)                    {                        case TypeCode.UInt16:                        case TypeCode.Int32:                        case TypeCode.UInt32:                        case TypeCode.Int64:                        case TypeCode.UInt64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.Int32:                    switch (tc)                    {                        case TypeCode.Int32:                        case TypeCode.Int64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.UInt32:                    switch (tc)                    {                        case TypeCode.UInt32:                        case TypeCode.Int64:                        case TypeCode.UInt64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.Int64:                    switch (tc)                    {                        case TypeCode.Int64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.UInt64:                    switch (tc)                    {                        case TypeCode.UInt64:                        case TypeCode.Single:                        case TypeCode.Double:                        case TypeCode.Decimal:                            return true;                    }                    break;                case TypeCode.Single:                    switch (tc)                    {                        case TypeCode.Single:                        case TypeCode.Double:                            return true;                    }                    break;                default:                    if (st == tt) return true;                    break;            }            return false;        }        static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)        {            bool better = false;            for (int i = 0; i < args.Length; i++)            {                int c = CompareConversions(args[i].Type,                    m1.Parameters[i].ParameterType,                    m2.Parameters[i].ParameterType);                if (c < 0) return false;                if (c > 0) better = true;            }            return better;        }        // 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        static int CompareConversions(Type s, Type t1, Type t2)        {            if (t1 == t2) return 0;            if (s == t1) return 1;            if (s == t2) return -1;            bool t1t2 = IsCompatibleWith(t1, t2);            bool t2t1 = IsCompatibleWith(t2, t1);            if (t1t2 && !t2t1) return 1;            if (t2t1 && !t1t2) return -1;            if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1;            if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1;            return 0;        }        Expression GenerateEqual(Expression left, Expression right)        {            return Expression.Equal(left, right);        }        Expression GenerateNotEqual(Expression left, Expression right)        {            return Expression.NotEqual(left, right);        }        Expression GenerateGreaterThan(Expression left, Expression right)        {            if (left.Type == typeof(string))            {                return Expression.GreaterThan(                    GenerateStaticMethodCall("Compare", left, right),                    Expression.Constant(0)                );            }            return Expression.GreaterThan(left, right);        }        Expression GenerateGreaterThanEqual(Expression left, Expression right)        {            if (left.Type == typeof(string))            {                return Expression.GreaterThanOrEqual(                    GenerateStaticMethodCall("Compare", left, right),                    Expression.Constant(0)                );            }            return Expression.GreaterThanOrEqual(left, right);        }        Expression GenerateLessThan(Expression left, Expression right)        {            if (left.Type == typeof(string))            {                return Expression.LessThan(                    GenerateStaticMethodCall("Compare", left, right),                    Expression.Constant(0)                );            }            return Expression.LessThan(left, right);        }        Expression GenerateLessThanEqual(Expression left, Expression right)        {            if (left.Type == typeof(string))            {                return Expression.LessThanOrEqual(                    GenerateStaticMethodCall("Compare", left, right),                    Expression.Constant(0)                );            }            return Expression.LessThanOrEqual(left, right);        }        Expression GenerateAdd(Expression left, Expression right)        {            if (left.Type == typeof(string) && right.Type == typeof(string))            {                return GenerateStaticMethodCall("Concat", left, right);            }            return Expression.Add(left, right);        }        Expression GenerateSubtract(Expression left, Expression right)        {            return Expression.Subtract(left, right);        }        Expression GenerateStringConcat(Expression left, Expression right)        {            return Expression.Call(                null,                typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),                new[] { left, right });        }        MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)        {            return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });        }        Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)        {            return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });        }        void SetTextPos(int pos)        {            textPos = pos;            ch = textPos < textLen ? text[textPos] : '\0';        }        void NextChar()        {            if (textPos < textLen) textPos++;            ch = textPos < textLen ? text[textPos] : '\0';        }        void NextToken()        {            while (Char.IsWhiteSpace(ch)) NextChar();            TokenId t;            int tokenPos = textPos;            switch (ch)            {                case '!':                    NextChar();                    if (ch == '=')                    {                        NextChar();                        t = TokenId.ExclamationEqual;                    }                    else                    {                        t = TokenId.Exclamation;                    }                    break;                case '%':                    NextChar();                    t = TokenId.Percent;                    break;                case '&':                    NextChar();                    if (ch == '&')                    {                        NextChar();                        t = TokenId.DoubleAmphersand;                    }                    else                    {                        t = TokenId.Amphersand;                    }                    break;                case '(':                    NextChar();                    t = TokenId.OpenParen;                    break;                case ')':                    NextChar();                    t = TokenId.CloseParen;                    break;                case '*':                    NextChar();                    t = TokenId.Asterisk;                    break;                case '+':                    NextChar();                    t = TokenId.Plus;                    break;                case ',':                    NextChar();                    t = TokenId.Comma;                    break;                case '-':                    NextChar();                    t = TokenId.Minus;                    break;                case '.':                    NextChar();                    t = TokenId.Dot;                    break;                case '/':                    NextChar();                    t = TokenId.Slash;                    break;                case ':':                    NextChar();                    t = TokenId.Colon;                    break;                case '<':                    NextChar();                    if (ch == '=')                    {                        NextChar();                        t = TokenId.LessThanEqual;                    }                    else if (ch == '>')                    {                        NextChar();                        t = TokenId.LessGreater;                    }                    else                    {                        t = TokenId.LessThan;                    }                    break;                case '=':                    NextChar();                    if (ch == '=')                    {                        NextChar();                        t = TokenId.DoubleEqual;                    }                    else                    {                        t = TokenId.Equal;                    }                    break;                case '>':                    NextChar();                    if (ch == '=')                    {                        NextChar();                        t = TokenId.GreaterThanEqual;                    }                    else                    {                        t = TokenId.GreaterThan;                    }                    break;                case '?':                    NextChar();                    t = TokenId.Question;                    break;                case '[':                    NextChar();                    t = TokenId.OpenBracket;                    break;                case ']':                    NextChar();                    t = TokenId.CloseBracket;                    break;                case '|':                    NextChar();                    if (ch == '|')                    {                        NextChar();                        t = TokenId.DoubleBar;                    }                    else                    {                        t = TokenId.Bar;                    }                    break;                case '"':                case '\'':                    char quote = ch;                    do                    {                        NextChar();                        while (textPos < textLen && ch != quote) NextChar();                        if (textPos == textLen)                            throw ParseError(textPos, Res.UnterminatedStringLiteral);                        NextChar();                    } while (ch == quote);                    t = TokenId.StringLiteral;                    break;                default:                    if (Char.IsLetter(ch) || ch == '@' || ch == '_')                    {                        do                        {                            NextChar();                        } while (Char.IsLetterOrDigit(ch) || ch == '_');                        t = TokenId.Identifier;                        break;                    }                    if (Char.IsDigit(ch))                    {                        t = TokenId.IntegerLiteral;                        do                        {                            NextChar();                        } while (Char.IsDigit(ch));                        if (ch == '.')                        {                            t = TokenId.RealLiteral;                            NextChar();                            ValidateDigit();                            do                            {                                NextChar();                            } while (Char.IsDigit(ch));                        }                        if (ch == 'E' || ch == 'e')                        {                            t = TokenId.RealLiteral;                            NextChar();                            if (ch == '+' || ch == '-') NextChar();                            ValidateDigit();                            do                            {                                NextChar();                            } while (Char.IsDigit(ch));                        }                        if (ch == 'F' || ch == 'f') NextChar();                        break;                    }                    if (textPos == textLen)                    {                        t = TokenId.End;                        break;                    }                    throw ParseError(textPos, Res.InvalidCharacter, ch);            }            token.id = t;            token.text = text.Substring(tokenPos, textPos - tokenPos);            token.pos = tokenPos;        }        bool TokenIdentifierIs(string id)        {            return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);        }        string GetIdentifier()        {            ValidateToken(TokenId.Identifier, Res.IdentifierExpected);            string id = token.text;            if (id.Length > 1 && id[0] == '@') id = id.Substring(1);            return id;        }        void ValidateDigit()        {            if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);        }        void ValidateToken(TokenId t, string errorMessage)        {            if (token.id != t) throw ParseError(errorMessage);        }        void ValidateToken(TokenId t)        {            if (token.id != t) throw ParseError(Res.SyntaxError);        }        Exception ParseError(string format, params object[] args)        {            return ParseError(token.pos, format, args);        }        Exception ParseError(int pos, string format, params object[] args)        {            return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);        }        static Dictionary<string, object> CreateKeywords()        {            Dictionary<string, object> d = new Dictionary<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);            foreach (Type type in predefinedTypes) d.Add(type.Name, type);            return d;        }    }    static class Res    {        public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";        public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";        public const string ExpressionExpected = "Expression expected";        public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";        public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'";        public const string InvalidRealLiteral = "Invalid real literal '{0}'";        public const string UnknownIdentifier = "Unknown identifier '{0}'";        public const string NoItInScope = "No 'it' is in scope";        public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments";        public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";        public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other";        public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other";        public const string MissingAsClause = "Expression is missing an 'as' clause";        public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";        public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form";        public const string NoMatchingConstructor = "No matching constructor in type '{0}'";        public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor";        public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'";        public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'";        public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible";        public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value";        public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'";        public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'";        public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists";        public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";        public const string InvalidIndex = "Array index must be an integer expression";        public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'";        public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'";        public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'";        public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'";        public const string UnterminatedStringLiteral = "Unterminated string literal";        public const string InvalidCharacter = "Syntax error '{0}'";        public const string DigitExpected = "Digit expected";        public const string SyntaxError = "Syntax error";        public const string TokenExpected = "{0} expected";        public const string ParseExceptionFormat = "{0} (at index {1})";        public const string ColonExpected = "':' expected";        public const string OpenParenExpected = "'(' expected";        public const string CloseParenOrOperatorExpected = "')' or operator expected";        public const string CloseParenOrCommaExpected = "')' or ',' expected";        public const string DotOrOpenParenExpected = "'.' or '(' expected";        public const string OpenBracketExpected = "'[' expected";        public const string CloseBracketOrCommaExpected = "']' or ',' expected";        public const string IdentifierExpected = "Identifier expected";    }}
调用示例(页面上方了一个GridView):
void BindGridTypeSafe()        {            NorthwindDataContext northwind = new NorthwindDataContext();            var query = from p in northwind.Products                        where p.CategoryID == 3 && p.UnitPrice > 3                        orderby p.SupplierID                        select p;            GridView1.DataSource = query;            GridView1.DataBind();        }        void BindGridDynamic()        {            NorthwindDataContext northwind = new NorthwindDataContext();            var query = northwind.Products                                 .Where("CategoryID = 3 AND UnitPrice > 3")                                 .OrderBy("SupplierID");            GridView1.DataSource = query;            GridView1.DataBind();        }


0 0
原创粉丝点击