DynamicQueryable.cs 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Text;
  8. using System.Threading;
  9. namespace TEAMModelOS.SDK.Helper.Query.LinqHelper
  10. {
  11. public static class DynamicQueryable
  12. {
  13. public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values)
  14. {
  15. return (IQueryable<T>)Where((IQueryable)source, predicate, values);
  16. }
  17. public static IQueryable Where(this IQueryable source, string predicate, params object[] values)
  18. {
  19. if (source == null) throw new ArgumentNullException("source");
  20. if (predicate == null) throw new ArgumentNullException("predicate");
  21. LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values);
  22. return source.Provider.CreateQuery(
  23. Expression.Call(
  24. typeof(Queryable), "Where",
  25. new Type[] { source.ElementType },
  26. source.Expression, Expression.Quote(lambda)));
  27. }
  28. public static IQueryable Select(this IQueryable source, string selector, params object[] values)
  29. {
  30. if (source == null) throw new ArgumentNullException("source");
  31. if (selector == null) throw new ArgumentNullException("selector");
  32. LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, null, selector, values);
  33. return source.Provider.CreateQuery(
  34. Expression.Call(
  35. typeof(Queryable), "Select",
  36. new Type[] { source.ElementType, lambda.Body.Type },
  37. source.Expression, Expression.Quote(lambda)));
  38. }
  39. public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
  40. {
  41. return (IQueryable<T>)OrderBy((IQueryable)source, ordering, values);
  42. }
  43. public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string ordering, params object[] values)
  44. {
  45. return (IQueryable<T>)ThenBy((IQueryable)source, ordering, values);
  46. }
  47. public static IQueryable ThenBy(this IQueryable source, string ordering, params object[] values)
  48. {
  49. if (source == null) throw new ArgumentNullException("source");
  50. if (ordering == null) throw new ArgumentNullException("ordering");
  51. ParameterExpression[] parameters = new ParameterExpression[] {
  52. Expression.Parameter(source.ElementType, "") };
  53. ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
  54. IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  55. Expression queryExpr = source.Expression;
  56. string methodAsc = "ThenBy";
  57. string methodDesc = "ThenByDescending";
  58. foreach (DynamicOrdering o in orderings)
  59. {
  60. queryExpr = Expression.Call(
  61. typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  62. new Type[] { source.ElementType, o.Selector.Type },
  63. queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
  64. }
  65. return source.Provider.CreateQuery(queryExpr);
  66. }
  67. public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values)
  68. {
  69. if (source == null) throw new ArgumentNullException("source");
  70. if (ordering == null) throw new ArgumentNullException("ordering");
  71. ParameterExpression[] parameters = new ParameterExpression[] {
  72. Expression.Parameter(source.ElementType, "") };
  73. ExpressionParser parser = new ExpressionParser(parameters, ordering, values);
  74. IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  75. Expression queryExpr = source.Expression;
  76. string methodAsc = "OrderBy";
  77. string methodDesc = "OrderByDescending";
  78. foreach (DynamicOrdering o in orderings)
  79. {
  80. queryExpr = Expression.Call(
  81. typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  82. new Type[] { source.ElementType, o.Selector.Type },
  83. queryExpr, Expression.Quote(Expression.Lambda(o.Selector, parameters)));
  84. methodAsc = "ThenBy";
  85. methodDesc = "ThenByDescending";
  86. }
  87. return source.Provider.CreateQuery(queryExpr);
  88. }
  89. public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, bool ascending)
  90. where T : class
  91. {
  92. Type type = typeof(T);
  93. PropertyInfo property = type.GetProperty(propertyName);
  94. if (property == null)
  95. throw new ArgumentException("propertyName", "Not Exist");
  96. ParameterExpression param = Expression.Parameter(type, "p");
  97. Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
  98. LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
  99. string methodName = ascending ? "OrderBy" : "OrderByDescending";
  100. MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
  101. new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
  102. return source.Provider.CreateQuery<T>(resultExp);
  103. }
  104. public static IQueryable Take(this IQueryable source, int count)
  105. {
  106. if (source == null) throw new ArgumentNullException("source");
  107. return source.Provider.CreateQuery(
  108. Expression.Call(
  109. typeof(Queryable), "Take",
  110. new Type[] { source.ElementType },
  111. source.Expression, Expression.Constant(count)));
  112. }
  113. public static IQueryable Skip(this IQueryable source, int count)
  114. {
  115. if (source == null) throw new ArgumentNullException("source");
  116. return source.Provider.CreateQuery(
  117. Expression.Call(
  118. typeof(Queryable), "Skip",
  119. new Type[] { source.ElementType },
  120. source.Expression, Expression.Constant(count)));
  121. }
  122. public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values)
  123. {
  124. if (source == null) throw new ArgumentNullException("source");
  125. if (keySelector == null) throw new ArgumentNullException("keySelector");
  126. if (elementSelector == null) throw new ArgumentNullException("elementSelector");
  127. LambdaExpression keyLambda = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values);
  128. LambdaExpression elementLambda = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values);
  129. return source.Provider.CreateQuery(
  130. Expression.Call(
  131. typeof(Queryable), "GroupBy",
  132. new Type[] { source.ElementType, keyLambda.Body.Type, elementLambda.Body.Type },
  133. source.Expression, Expression.Quote(keyLambda), Expression.Quote(elementLambda)));
  134. }
  135. public static bool Any(this IQueryable source)
  136. {
  137. if (source == null) throw new ArgumentNullException("source");
  138. return (bool)source.Provider.Execute(
  139. Expression.Call(
  140. typeof(Queryable), "Any",
  141. new Type[] { source.ElementType }, source.Expression));
  142. }
  143. public static int Count(this IQueryable source)
  144. {
  145. if (source == null) throw new ArgumentNullException("source");
  146. return (int)source.Provider.Execute(
  147. Expression.Call(
  148. typeof(Queryable), "Count",
  149. new Type[] { source.ElementType }, source.Expression));
  150. }
  151. }
  152. public abstract class DynamicClass
  153. {
  154. public override string ToString()
  155. {
  156. PropertyInfo[] props = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
  157. StringBuilder sb = new StringBuilder();
  158. sb.Append("{");
  159. for (int i = 0; i < props.Length; i++)
  160. {
  161. if (i > 0) sb.Append(", ");
  162. sb.Append(props[i].Name);
  163. sb.Append("=");
  164. sb.Append(props[i].GetValue(this, null));
  165. }
  166. sb.Append("}");
  167. return sb.ToString();
  168. }
  169. }
  170. public class DynamicProperty
  171. {
  172. string name;
  173. Type type;
  174. public DynamicProperty(string name, Type type)
  175. {
  176. if (name == null) throw new ArgumentNullException("name");
  177. if (type == null) throw new ArgumentNullException("type");
  178. this.name = name;
  179. this.type = type;
  180. }
  181. public string Name
  182. {
  183. get { return name; }
  184. }
  185. public Type Type
  186. {
  187. get { return type; }
  188. }
  189. }
  190. public static class DynamicExpression
  191. {
  192. public static Expression Parse(Type resultType, string expression, params object[] values)
  193. {
  194. ExpressionParser parser = new ExpressionParser(null, expression, values);
  195. return parser.Parse(resultType);
  196. }
  197. public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values)
  198. {
  199. return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, values);
  200. }
  201. public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values)
  202. {
  203. ExpressionParser parser = new ExpressionParser(parameters, expression, values);
  204. return Expression.Lambda(parser.Parse(resultType), parameters);
  205. }
  206. public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values)
  207. {
  208. return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values);
  209. }
  210. public static Type CreateClass(params DynamicProperty[] properties)
  211. {
  212. return ClassFactory.Instance.GetDynamicClass(properties);
  213. }
  214. public static Type CreateClass(IEnumerable<DynamicProperty> properties)
  215. {
  216. return ClassFactory.Instance.GetDynamicClass(properties);
  217. }
  218. }
  219. internal class DynamicOrdering
  220. {
  221. public Expression Selector;
  222. public bool Ascending;
  223. }
  224. internal class Signature : IEquatable<Signature>
  225. {
  226. public DynamicProperty[] properties;
  227. public int hashCode;
  228. public Signature(IEnumerable<DynamicProperty> properties)
  229. {
  230. this.properties = properties.ToArray();
  231. hashCode = 0;
  232. foreach (DynamicProperty p in properties)
  233. {
  234. hashCode ^= p.Name.GetHashCode() ^ p.Type.GetHashCode();
  235. }
  236. }
  237. public override int GetHashCode()
  238. {
  239. return hashCode;
  240. }
  241. public override bool Equals(object obj)
  242. {
  243. return obj is Signature ? Equals((Signature)obj) : false;
  244. }
  245. public bool Equals(Signature other)
  246. {
  247. if (properties.Length != other.properties.Length) return false;
  248. for (int i = 0; i < properties.Length; i++)
  249. {
  250. if (properties[i].Name != other.properties[i].Name ||
  251. properties[i].Type != other.properties[i].Type) return false;
  252. }
  253. return true;
  254. }
  255. }
  256. internal class ClassFactory
  257. {
  258. public static readonly ClassFactory Instance = new ClassFactory();
  259. static ClassFactory() { } // Trigger lazy initialization of static fields
  260. ModuleBuilder module;
  261. Dictionary<Signature, Type> classes;
  262. int classCount;
  263. ReaderWriterLock rwLock;
  264. private ClassFactory()
  265. {
  266. AssemblyName name = new AssemblyName("DynamicClasses");
  267. AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  268. // AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  269. #if ENABLE_LINQ_PARTIAL_TRUST
  270. new ReflectionPermission(PermissionState.Unrestricted).Assert();
  271. #endif
  272. try
  273. {
  274. module = assembly.DefineDynamicModule("Module");
  275. }
  276. finally
  277. {
  278. #if ENABLE_LINQ_PARTIAL_TRUST
  279. PermissionSet.RevertAssert();
  280. #endif
  281. }
  282. classes = new Dictionary<Signature, Type>();
  283. rwLock = new ReaderWriterLock();
  284. }
  285. public Type GetDynamicClass(IEnumerable<DynamicProperty> properties)
  286. {
  287. rwLock.AcquireReaderLock(Timeout.Infinite);
  288. try
  289. {
  290. Signature signature = new Signature(properties);
  291. Type type;
  292. if (!classes.TryGetValue(signature, out type))
  293. {
  294. type = CreateDynamicClass(signature.properties);
  295. classes.Add(signature, type);
  296. }
  297. return type;
  298. }
  299. finally
  300. {
  301. rwLock.ReleaseReaderLock();
  302. }
  303. }
  304. Type CreateDynamicClass(DynamicProperty[] properties)
  305. {
  306. LockCookie cookie = rwLock.UpgradeToWriterLock(Timeout.Infinite);
  307. try
  308. {
  309. string typeName = "DynamicClass" + (classCount + 1);
  310. #if ENABLE_LINQ_PARTIAL_TRUST
  311. new ReflectionPermission(PermissionState.Unrestricted).Assert();
  312. #endif
  313. try
  314. {
  315. TypeBuilder tb = this.module.DefineType(typeName, TypeAttributes.Class |
  316. TypeAttributes.Public, typeof(DynamicClass));
  317. FieldInfo[] fields = GenerateProperties(tb, properties);
  318. GenerateEquals(tb, fields);
  319. GenerateGetHashCode(tb, fields);
  320. Type result = tb.CreateType();
  321. classCount++;
  322. return result;
  323. }
  324. finally
  325. {
  326. #if ENABLE_LINQ_PARTIAL_TRUST
  327. PermissionSet.RevertAssert();
  328. #endif
  329. }
  330. }
  331. finally
  332. {
  333. rwLock.DowngradeFromWriterLock(ref cookie);
  334. }
  335. }
  336. FieldInfo[] GenerateProperties(TypeBuilder tb, DynamicProperty[] properties)
  337. {
  338. FieldInfo[] fields = new FieldBuilder[properties.Length];
  339. for (int i = 0; i < properties.Length; i++)
  340. {
  341. DynamicProperty dp = properties[i];
  342. FieldBuilder fb = tb.DefineField("_" + dp.Name, dp.Type, FieldAttributes.Private);
  343. PropertyBuilder pb = tb.DefineProperty(dp.Name, PropertyAttributes.HasDefault, dp.Type, null);
  344. MethodBuilder mbGet = tb.DefineMethod("get_" + dp.Name,
  345. MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
  346. dp.Type, Type.EmptyTypes);
  347. ILGenerator genGet = mbGet.GetILGenerator();
  348. genGet.Emit(OpCodes.Ldarg_0);
  349. genGet.Emit(OpCodes.Ldfld, fb);
  350. genGet.Emit(OpCodes.Ret);
  351. MethodBuilder mbSet = tb.DefineMethod("set_" + dp.Name,
  352. MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
  353. null, new Type[] { dp.Type });
  354. ILGenerator genSet = mbSet.GetILGenerator();
  355. genSet.Emit(OpCodes.Ldarg_0);
  356. genSet.Emit(OpCodes.Ldarg_1);
  357. genSet.Emit(OpCodes.Stfld, fb);
  358. genSet.Emit(OpCodes.Ret);
  359. pb.SetGetMethod(mbGet);
  360. pb.SetSetMethod(mbSet);
  361. fields[i] = fb;
  362. }
  363. return fields;
  364. }
  365. void GenerateEquals(TypeBuilder tb, FieldInfo[] fields)
  366. {
  367. MethodBuilder mb = tb.DefineMethod("Equals",
  368. MethodAttributes.Public | MethodAttributes.ReuseSlot |
  369. MethodAttributes.Virtual | MethodAttributes.HideBySig,
  370. typeof(bool), new Type[] { typeof(object) });
  371. ILGenerator gen = mb.GetILGenerator();
  372. LocalBuilder other = gen.DeclareLocal(tb);
  373. Label next = gen.DefineLabel();
  374. gen.Emit(OpCodes.Ldarg_1);
  375. gen.Emit(OpCodes.Isinst, tb);
  376. gen.Emit(OpCodes.Stloc, other);
  377. gen.Emit(OpCodes.Ldloc, other);
  378. gen.Emit(OpCodes.Brtrue_S, next);
  379. gen.Emit(OpCodes.Ldc_I4_0);
  380. gen.Emit(OpCodes.Ret);
  381. gen.MarkLabel(next);
  382. foreach (FieldInfo field in fields)
  383. {
  384. Type ft = field.FieldType;
  385. Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
  386. next = gen.DefineLabel();
  387. gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
  388. gen.Emit(OpCodes.Ldarg_0);
  389. gen.Emit(OpCodes.Ldfld, field);
  390. gen.Emit(OpCodes.Ldloc, other);
  391. gen.Emit(OpCodes.Ldfld, field);
  392. gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("Equals", new Type[] { ft, ft }), null);
  393. gen.Emit(OpCodes.Brtrue_S, next);
  394. gen.Emit(OpCodes.Ldc_I4_0);
  395. gen.Emit(OpCodes.Ret);
  396. gen.MarkLabel(next);
  397. }
  398. gen.Emit(OpCodes.Ldc_I4_1);
  399. gen.Emit(OpCodes.Ret);
  400. }
  401. void GenerateGetHashCode(TypeBuilder tb, FieldInfo[] fields)
  402. {
  403. MethodBuilder mb = tb.DefineMethod("GetHashCode",
  404. MethodAttributes.Public | MethodAttributes.ReuseSlot |
  405. MethodAttributes.Virtual | MethodAttributes.HideBySig,
  406. typeof(int), Type.EmptyTypes);
  407. ILGenerator gen = mb.GetILGenerator();
  408. gen.Emit(OpCodes.Ldc_I4_0);
  409. foreach (FieldInfo field in fields)
  410. {
  411. Type ft = field.FieldType;
  412. Type ct = typeof(EqualityComparer<>).MakeGenericType(ft);
  413. gen.EmitCall(OpCodes.Call, ct.GetMethod("get_Default"), null);
  414. gen.Emit(OpCodes.Ldarg_0);
  415. gen.Emit(OpCodes.Ldfld, field);
  416. gen.EmitCall(OpCodes.Callvirt, ct.GetMethod("GetHashCode", new Type[] { ft }), null);
  417. gen.Emit(OpCodes.Xor);
  418. }
  419. gen.Emit(OpCodes.Ret);
  420. }
  421. }
  422. public sealed class ParseException : Exception
  423. {
  424. int position;
  425. public ParseException(string message, int position)
  426. : base(message)
  427. {
  428. this.position = position;
  429. }
  430. public int Position
  431. {
  432. get { return position; }
  433. }
  434. public override string ToString()
  435. {
  436. return string.Format(Res.ParseExceptionFormat, Message, position);
  437. }
  438. }
  439. internal class ExpressionParser
  440. {
  441. struct Token
  442. {
  443. public TokenId id;
  444. public string text;
  445. public int pos;
  446. }
  447. enum TokenId
  448. {
  449. Unknown,
  450. End,
  451. Identifier,
  452. StringLiteral,
  453. IntegerLiteral,
  454. RealLiteral,
  455. Exclamation,
  456. Percent,
  457. Amphersand,
  458. OpenParen,
  459. CloseParen,
  460. Asterisk,
  461. Plus,
  462. Comma,
  463. Minus,
  464. Dot,
  465. Slash,
  466. Colon,
  467. LessThan,
  468. Equal,
  469. GreaterThan,
  470. Question,
  471. OpenBracket,
  472. CloseBracket,
  473. Bar,
  474. ExclamationEqual,
  475. DoubleAmphersand,
  476. LessThanEqual,
  477. LessGreater,
  478. DoubleEqual,
  479. GreaterThanEqual,
  480. DoubleBar
  481. }
  482. interface ILogicalSignatures
  483. {
  484. void F(bool x, bool y);
  485. void F(bool? x, bool? y);
  486. }
  487. interface IArithmeticSignatures
  488. {
  489. void F(int x, int y);
  490. void F(uint x, uint y);
  491. void F(long x, long y);
  492. void F(ulong x, ulong y);
  493. void F(float x, float y);
  494. void F(double x, double y);
  495. void F(decimal x, decimal y);
  496. void F(int? x, int? y);
  497. void F(uint? x, uint? y);
  498. void F(long? x, long? y);
  499. void F(ulong? x, ulong? y);
  500. void F(float? x, float? y);
  501. void F(double? x, double? y);
  502. void F(decimal? x, decimal? y);
  503. }
  504. interface IRelationalSignatures : IArithmeticSignatures
  505. {
  506. void F(string x, string y);
  507. void F(char x, char y);
  508. void F(DateTime x, DateTime y);
  509. void F(TimeSpan x, TimeSpan y);
  510. void F(char? x, char? y);
  511. void F(DateTime? x, DateTime? y);
  512. void F(TimeSpan? x, TimeSpan? y);
  513. }
  514. interface IEqualitySignatures : IRelationalSignatures
  515. {
  516. void F(bool x, bool y);
  517. void F(bool? x, bool? y);
  518. }
  519. interface IAddSignatures : IArithmeticSignatures
  520. {
  521. void F(DateTime x, TimeSpan y);
  522. void F(TimeSpan x, TimeSpan y);
  523. void F(DateTime? x, TimeSpan? y);
  524. void F(TimeSpan? x, TimeSpan? y);
  525. }
  526. interface ISubtractSignatures : IAddSignatures
  527. {
  528. void F(DateTime x, DateTime y);
  529. void F(DateTime? x, DateTime? y);
  530. }
  531. interface INegationSignatures
  532. {
  533. void F(int x);
  534. void F(long x);
  535. void F(float x);
  536. void F(double x);
  537. void F(decimal x);
  538. void F(int? x);
  539. void F(long? x);
  540. void F(float? x);
  541. void F(double? x);
  542. void F(decimal? x);
  543. }
  544. interface INotSignatures
  545. {
  546. void F(bool x);
  547. void F(bool? x);
  548. }
  549. interface IEnumerableSignatures
  550. {
  551. void Where(bool predicate);
  552. void Any();
  553. void Any(bool predicate);
  554. void All(bool predicate);
  555. void Count();
  556. void Count(bool predicate);
  557. void Min(object selector);
  558. void Max(object selector);
  559. void Sum(int selector);
  560. void Sum(int? selector);
  561. void Sum(long selector);
  562. void Sum(long? selector);
  563. void Sum(float selector);
  564. void Sum(float? selector);
  565. void Sum(double selector);
  566. void Sum(double? selector);
  567. void Sum(decimal selector);
  568. void Sum(decimal? selector);
  569. void Average(int selector);
  570. void Average(int? selector);
  571. void Average(long selector);
  572. void Average(long? selector);
  573. void Average(float selector);
  574. void Average(float? selector);
  575. void Average(double selector);
  576. void Average(double? selector);
  577. void Average(decimal selector);
  578. void Average(decimal? selector);
  579. }
  580. static readonly Type[] predefinedTypes = {
  581. typeof(Object),
  582. typeof(Boolean),
  583. typeof(Char),
  584. typeof(String),
  585. typeof(SByte),
  586. typeof(Byte),
  587. typeof(Int16),
  588. typeof(UInt16),
  589. typeof(Int32),
  590. typeof(UInt32),
  591. typeof(Int64),
  592. typeof(UInt64),
  593. typeof(Single),
  594. typeof(Double),
  595. typeof(Decimal),
  596. typeof(DateTime),
  597. typeof(TimeSpan),
  598. typeof(Guid),
  599. typeof(Math),
  600. typeof(Convert)
  601. };
  602. static readonly Expression trueLiteral = Expression.Constant(true);
  603. static readonly Expression falseLiteral = Expression.Constant(false);
  604. static readonly Expression nullLiteral = Expression.Constant(null);
  605. static readonly string keywordIt = "it";
  606. static readonly string keywordIif = "iif";
  607. static readonly string keywordNew = "new";
  608. static Dictionary<string, object> keywords;
  609. Dictionary<string, object> symbols;
  610. IDictionary<string, object> externals;
  611. Dictionary<Expression, string> literals;
  612. ParameterExpression it;
  613. string text;
  614. int textPos;
  615. int textLen;
  616. char ch;
  617. Token token;
  618. public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
  619. {
  620. if (expression == null) throw new ArgumentNullException("expression");
  621. if (keywords == null) keywords = CreateKeywords();
  622. symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  623. literals = new Dictionary<Expression, string>();
  624. if (parameters != null) ProcessParameters(parameters);
  625. if (values != null) ProcessValues(values);
  626. text = expression;
  627. textLen = text.Length;
  628. SetTextPos(0);
  629. NextToken();
  630. }
  631. void ProcessParameters(ParameterExpression[] parameters)
  632. {
  633. foreach (ParameterExpression pe in parameters)
  634. if (!String.IsNullOrEmpty(pe.Name))
  635. AddSymbol(pe.Name, pe);
  636. if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
  637. it = parameters[0];
  638. }
  639. void ProcessValues(object[] values)
  640. {
  641. for (int i = 0; i < values.Length; i++)
  642. {
  643. object value = values[i];
  644. if (i == values.Length - 1 && value is IDictionary<string, object>)
  645. {
  646. externals = (IDictionary<string, object>)value;
  647. }
  648. else
  649. {
  650. AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
  651. }
  652. }
  653. }
  654. void AddSymbol(string name, object value)
  655. {
  656. if (symbols.ContainsKey(name))
  657. throw ParseError(Res.DuplicateIdentifier, name);
  658. symbols.Add(name, value);
  659. }
  660. public Expression Parse(Type resultType)
  661. {
  662. int exprPos = token.pos;
  663. Expression expr = ParseExpression();
  664. if (resultType != null)
  665. if ((expr = PromoteExpression(expr, resultType, true)) == null)
  666. throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));
  667. ValidateToken(TokenId.End, Res.SyntaxError);
  668. return expr;
  669. }
  670. #pragma warning disable 0219
  671. public IEnumerable<DynamicOrdering> ParseOrdering()
  672. {
  673. List<DynamicOrdering> orderings = new List<DynamicOrdering>();
  674. while (true)
  675. {
  676. Expression expr = ParseExpression();
  677. bool ascending = true;
  678. if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
  679. {
  680. NextToken();
  681. }
  682. else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
  683. {
  684. NextToken();
  685. ascending = false;
  686. }
  687. orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
  688. if (token.id != TokenId.Comma) break;
  689. NextToken();
  690. }
  691. ValidateToken(TokenId.End, Res.SyntaxError);
  692. return orderings;
  693. }
  694. #pragma warning restore 0219
  695. // ?: operator
  696. Expression ParseExpression()
  697. {
  698. int errorPos = token.pos;
  699. Expression expr = ParseLogicalOr();
  700. if (token.id == TokenId.Question)
  701. {
  702. NextToken();
  703. Expression expr1 = ParseExpression();
  704. ValidateToken(TokenId.Colon, Res.ColonExpected);
  705. NextToken();
  706. Expression expr2 = ParseExpression();
  707. expr = GenerateConditional(expr, expr1, expr2, errorPos);
  708. }
  709. return expr;
  710. }
  711. // ||, or operator
  712. Expression ParseLogicalOr()
  713. {
  714. Expression left = ParseLogicalAnd();
  715. while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
  716. {
  717. Token op = token;
  718. NextToken();
  719. Expression right = ParseLogicalAnd();
  720. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  721. left = Expression.OrElse(left, right);
  722. }
  723. return left;
  724. }
  725. // &&, and operator
  726. Expression ParseLogicalAnd()
  727. {
  728. Expression left = ParseComparison();
  729. while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
  730. {
  731. Token op = token;
  732. NextToken();
  733. Expression right = ParseComparison();
  734. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  735. left = Expression.AndAlso(left, right);
  736. }
  737. return left;
  738. }
  739. // =, ==, !=, <>, >, >=, <, <= operators
  740. Expression ParseComparison()
  741. {
  742. Expression left = ParseAdditive();
  743. while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||
  744. token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||
  745. token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||
  746. token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual)
  747. {
  748. Token op = token;
  749. NextToken();
  750. Expression right = ParseAdditive();
  751. bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||
  752. op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;
  753. if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)
  754. {
  755. if (left.Type != right.Type)
  756. {
  757. if (left.Type.IsAssignableFrom(right.Type))
  758. {
  759. right = Expression.Convert(right, left.Type);
  760. }
  761. else if (right.Type.IsAssignableFrom(left.Type))
  762. {
  763. left = Expression.Convert(left, right.Type);
  764. }
  765. else
  766. {
  767. throw IncompatibleOperandsError(op.text, left, right, op.pos);
  768. }
  769. }
  770. }
  771. else if (IsEnumType(left.Type) || IsEnumType(right.Type))
  772. {
  773. if (left.Type != right.Type)
  774. {
  775. Expression e;
  776. if ((e = PromoteExpression(right, left.Type, true)) != null)
  777. {
  778. right = e;
  779. }
  780. else if ((e = PromoteExpression(left, right.Type, true)) != null)
  781. {
  782. left = e;
  783. }
  784. else
  785. {
  786. throw IncompatibleOperandsError(op.text, left, right, op.pos);
  787. }
  788. }
  789. }
  790. else
  791. {
  792. CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
  793. op.text, ref left, ref right, op.pos);
  794. }
  795. switch (op.id)
  796. {
  797. case TokenId.Equal:
  798. case TokenId.DoubleEqual:
  799. left = GenerateEqual(left, right);
  800. break;
  801. case TokenId.ExclamationEqual:
  802. case TokenId.LessGreater:
  803. left = GenerateNotEqual(left, right);
  804. break;
  805. case TokenId.GreaterThan:
  806. left = GenerateGreaterThan(left, right);
  807. break;
  808. case TokenId.GreaterThanEqual:
  809. left = GenerateGreaterThanEqual(left, right);
  810. break;
  811. case TokenId.LessThan:
  812. left = GenerateLessThan(left, right);
  813. break;
  814. case TokenId.LessThanEqual:
  815. left = GenerateLessThanEqual(left, right);
  816. break;
  817. }
  818. }
  819. return left;
  820. }
  821. // +, -, & operators
  822. Expression ParseAdditive()
  823. {
  824. Expression left = ParseMultiplicative();
  825. while (token.id == TokenId.Plus || token.id == TokenId.Minus ||
  826. token.id == TokenId.Amphersand)
  827. {
  828. Token op = token;
  829. NextToken();
  830. Expression right = ParseMultiplicative();
  831. switch (op.id)
  832. {
  833. case TokenId.Plus:
  834. if (left.Type == typeof(string) || right.Type == typeof(string))
  835. goto case TokenId.Amphersand;
  836. CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos);
  837. left = GenerateAdd(left, right);
  838. break;
  839. case TokenId.Minus:
  840. CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos);
  841. left = GenerateSubtract(left, right);
  842. break;
  843. case TokenId.Amphersand:
  844. left = GenerateStringConcat(left, right);
  845. break;
  846. }
  847. }
  848. return left;
  849. }
  850. // *, /, %, mod operators
  851. Expression ParseMultiplicative()
  852. {
  853. Expression left = ParseUnary();
  854. while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||
  855. token.id == TokenId.Percent || TokenIdentifierIs("mod"))
  856. {
  857. Token op = token;
  858. NextToken();
  859. Expression right = ParseUnary();
  860. CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos);
  861. switch (op.id)
  862. {
  863. case TokenId.Asterisk:
  864. left = Expression.Multiply(left, right);
  865. break;
  866. case TokenId.Slash:
  867. left = Expression.Divide(left, right);
  868. break;
  869. case TokenId.Percent:
  870. case TokenId.Identifier:
  871. left = Expression.Modulo(left, right);
  872. break;
  873. }
  874. }
  875. return left;
  876. }
  877. // -, !, not unary operators
  878. Expression ParseUnary()
  879. {
  880. if (token.id == TokenId.Minus || token.id == TokenId.Exclamation ||
  881. TokenIdentifierIs("not"))
  882. {
  883. Token op = token;
  884. NextToken();
  885. if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral ||
  886. token.id == TokenId.RealLiteral))
  887. {
  888. token.text = "-" + token.text;
  889. token.pos = op.pos;
  890. return ParsePrimary();
  891. }
  892. Expression expr = ParseUnary();
  893. if (op.id == TokenId.Minus)
  894. {
  895. CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos);
  896. expr = Expression.Negate(expr);
  897. }
  898. else
  899. {
  900. CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos);
  901. expr = Expression.Not(expr);
  902. }
  903. return expr;
  904. }
  905. return ParsePrimary();
  906. }
  907. Expression ParsePrimary()
  908. {
  909. Expression expr = ParsePrimaryStart();
  910. while (true)
  911. {
  912. if (token.id == TokenId.Dot)
  913. {
  914. NextToken();
  915. expr = ParseMemberAccess(null, expr);
  916. }
  917. else if (token.id == TokenId.OpenBracket)
  918. {
  919. expr = ParseElementAccess(expr);
  920. }
  921. else
  922. {
  923. break;
  924. }
  925. }
  926. return expr;
  927. }
  928. Expression ParsePrimaryStart()
  929. {
  930. switch (token.id)
  931. {
  932. case TokenId.Identifier:
  933. return ParseIdentifier();
  934. case TokenId.StringLiteral:
  935. return ParseStringLiteral();
  936. case TokenId.IntegerLiteral:
  937. return ParseIntegerLiteral();
  938. case TokenId.RealLiteral:
  939. return ParseRealLiteral();
  940. case TokenId.OpenParen:
  941. return ParseParenExpression();
  942. default:
  943. throw ParseError(Res.ExpressionExpected);
  944. }
  945. }
  946. Expression ParseStringLiteral()
  947. {
  948. ValidateToken(TokenId.StringLiteral);
  949. char quote = token.text[0];
  950. string s = token.text.Substring(1, token.text.Length - 2);
  951. int start = 0;
  952. while (true)
  953. {
  954. int i = s.IndexOf(quote, start);
  955. if (i < 0) break;
  956. s = s.Remove(i, 1);
  957. start = i + 1;
  958. }
  959. //if (quote == '\'') {
  960. // if (s.Length != 1)
  961. // throw ParseError(Res.InvalidCharacterLiteral);
  962. // NextToken();
  963. // return CreateLiteral(s[0], s);
  964. //}
  965. NextToken();
  966. return CreateLiteral(s, s);
  967. }
  968. Expression ParseIntegerLiteral()
  969. {
  970. ValidateToken(TokenId.IntegerLiteral);
  971. string text = token.text;
  972. if (text[0] != '-')
  973. {
  974. ulong value;
  975. if (!UInt64.TryParse(text, out value))
  976. throw ParseError(Res.InvalidIntegerLiteral, text);
  977. NextToken();
  978. if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text);
  979. if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text);
  980. if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text);
  981. return CreateLiteral(value, text);
  982. }
  983. else
  984. {
  985. long value;
  986. if (!Int64.TryParse(text, out value))
  987. throw ParseError(Res.InvalidIntegerLiteral, text);
  988. NextToken();
  989. if (value >= Int32.MinValue && value <= Int32.MaxValue)
  990. return CreateLiteral((int)value, text);
  991. return CreateLiteral(value, text);
  992. }
  993. }
  994. Expression ParseRealLiteral()
  995. {
  996. ValidateToken(TokenId.RealLiteral);
  997. string text = token.text;
  998. object value = null;
  999. char last = text[text.Length - 1];
  1000. if (last == 'F' || last == 'f')
  1001. {
  1002. float f;
  1003. if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f;
  1004. }
  1005. else
  1006. {
  1007. double d;
  1008. if (Double.TryParse(text, out d)) value = d;
  1009. }
  1010. if (value == null) throw ParseError(Res.InvalidRealLiteral, text);
  1011. NextToken();
  1012. return CreateLiteral(value, text);
  1013. }
  1014. Expression CreateLiteral(object value, string text)
  1015. {
  1016. ConstantExpression expr = Expression.Constant(value);
  1017. literals.Add(expr, text);
  1018. return expr;
  1019. }
  1020. Expression ParseParenExpression()
  1021. {
  1022. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1023. NextToken();
  1024. Expression e = ParseExpression();
  1025. ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);
  1026. NextToken();
  1027. return e;
  1028. }
  1029. Expression ParseIdentifier()
  1030. {
  1031. ValidateToken(TokenId.Identifier);
  1032. object value;
  1033. if (keywords.TryGetValue(token.text, out value))
  1034. {
  1035. if (value is Type) return ParseTypeAccess((Type)value);
  1036. if (value == (object)keywordIt) return ParseIt();
  1037. if (value == (object)keywordIif) return ParseIif();
  1038. if (value == (object)keywordNew) return ParseNew();
  1039. NextToken();
  1040. return (Expression)value;
  1041. }
  1042. if (symbols.TryGetValue(token.text, out value) ||
  1043. externals != null && externals.TryGetValue(token.text, out value))
  1044. {
  1045. Expression expr = value as Expression;
  1046. if (expr == null)
  1047. {
  1048. expr = Expression.Constant(value);
  1049. }
  1050. else
  1051. {
  1052. LambdaExpression lambda = expr as LambdaExpression;
  1053. if (lambda != null) return ParseLambdaInvocation(lambda);
  1054. }
  1055. NextToken();
  1056. return expr;
  1057. }
  1058. if (it != null) return ParseMemberAccess(null, it);
  1059. throw ParseError(Res.UnknownIdentifier, token.text);
  1060. }
  1061. Expression ParseIt()
  1062. {
  1063. if (it == null)
  1064. throw ParseError(Res.NoItInScope);
  1065. NextToken();
  1066. return it;
  1067. }
  1068. Expression ParseIif()
  1069. {
  1070. int errorPos = token.pos;
  1071. NextToken();
  1072. Expression[] args = ParseArgumentList();
  1073. if (args.Length != 3)
  1074. throw ParseError(errorPos, Res.IifRequiresThreeArgs);
  1075. return GenerateConditional(args[0], args[1], args[2], errorPos);
  1076. }
  1077. Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
  1078. {
  1079. if (test.Type != typeof(bool))
  1080. throw ParseError(errorPos, Res.FirstExprMustBeBool);
  1081. if (expr1.Type != expr2.Type)
  1082. {
  1083. Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
  1084. Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
  1085. if (expr1as2 != null && expr2as1 == null)
  1086. {
  1087. expr1 = expr1as2;
  1088. }
  1089. else if (expr2as1 != null && expr1as2 == null)
  1090. {
  1091. expr2 = expr2as1;
  1092. }
  1093. else
  1094. {
  1095. string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";
  1096. string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";
  1097. if (expr1as2 != null && expr2as1 != null)
  1098. throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2);
  1099. throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2);
  1100. }
  1101. }
  1102. return Expression.Condition(test, expr1, expr2);
  1103. }
  1104. Expression ParseNew()
  1105. {
  1106. NextToken();
  1107. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1108. NextToken();
  1109. List<DynamicProperty> properties = new List<DynamicProperty>();
  1110. List<Expression> expressions = new List<Expression>();
  1111. while (true)
  1112. {
  1113. int exprPos = token.pos;
  1114. Expression expr = ParseExpression();
  1115. string propName;
  1116. if (TokenIdentifierIs("as"))
  1117. {
  1118. NextToken();
  1119. propName = GetIdentifier();
  1120. NextToken();
  1121. }
  1122. else
  1123. {
  1124. MemberExpression me = expr as MemberExpression;
  1125. if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
  1126. propName = me.Member.Name;
  1127. }
  1128. expressions.Add(expr);
  1129. properties.Add(new DynamicProperty(propName, expr.Type));
  1130. if (token.id != TokenId.Comma) break;
  1131. NextToken();
  1132. }
  1133. ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
  1134. NextToken();
  1135. Type type = DynamicExpression.CreateClass(properties);
  1136. MemberBinding[] bindings = new MemberBinding[properties.Count];
  1137. for (int i = 0; i < bindings.Length; i++)
  1138. bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
  1139. return Expression.MemberInit(Expression.New(type), bindings);
  1140. }
  1141. Expression ParseLambdaInvocation(LambdaExpression lambda)
  1142. {
  1143. int errorPos = token.pos;
  1144. NextToken();
  1145. Expression[] args = ParseArgumentList();
  1146. MethodBase method;
  1147. if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1)
  1148. throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda);
  1149. return Expression.Invoke(lambda, args);
  1150. }
  1151. Expression ParseTypeAccess(Type type)
  1152. {
  1153. int errorPos = token.pos;
  1154. NextToken();
  1155. if (token.id == TokenId.Question)
  1156. {
  1157. if (!type.IsValueType || IsNullableType(type))
  1158. throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type));
  1159. type = typeof(Nullable<>).MakeGenericType(type);
  1160. NextToken();
  1161. }
  1162. if (token.id == TokenId.OpenParen)
  1163. {
  1164. Expression[] args = ParseArgumentList();
  1165. MethodBase method;
  1166. switch (FindBestMethod(type.GetConstructors(), args, out method))
  1167. {
  1168. case 0:
  1169. if (args.Length == 1)
  1170. return GenerateConversion(args[0], type, errorPos);
  1171. throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));
  1172. case 1:
  1173. return Expression.New((ConstructorInfo)method, args);
  1174. default:
  1175. throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));
  1176. }
  1177. }
  1178. ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);
  1179. NextToken();
  1180. return ParseMemberAccess(type, null);
  1181. }
  1182. Expression GenerateConversion(Expression expr, Type type, int errorPos)
  1183. {
  1184. Type exprType = expr.Type;
  1185. if (exprType == type) return expr;
  1186. if (exprType.IsValueType && type.IsValueType)
  1187. {
  1188. if ((IsNullableType(exprType) || IsNullableType(type)) &&
  1189. GetNonNullableType(exprType) == GetNonNullableType(type))
  1190. return Expression.Convert(expr, type);
  1191. if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
  1192. (IsNumericType(type)) || IsEnumType(type))
  1193. return Expression.ConvertChecked(expr, type);
  1194. }
  1195. if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
  1196. exprType.IsInterface || type.IsInterface)
  1197. return Expression.Convert(expr, type);
  1198. throw ParseError(errorPos, Res.CannotConvertValue,
  1199. GetTypeName(exprType), GetTypeName(type));
  1200. }
  1201. Expression ParseMemberAccess(Type type, Expression instance)
  1202. {
  1203. if (instance != null) type = instance.Type;
  1204. int errorPos = token.pos;
  1205. string id = GetIdentifier();
  1206. NextToken();
  1207. if (token.id == TokenId.OpenParen)
  1208. {
  1209. if (instance != null && type != typeof(string))
  1210. {
  1211. Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);
  1212. if (enumerableType != null)
  1213. {
  1214. Type elementType = enumerableType.GetGenericArguments()[0];
  1215. return ParseAggregate(instance, elementType, id, errorPos);
  1216. }
  1217. }
  1218. Expression[] args = ParseArgumentList();
  1219. MethodBase mb;
  1220. switch (FindMethod(type, id, instance == null, args, out mb))
  1221. {
  1222. case 0:
  1223. throw ParseError(errorPos, Res.NoApplicableMethod,
  1224. id, GetTypeName(type));
  1225. case 1:
  1226. MethodInfo method = (MethodInfo)mb;
  1227. if (!IsPredefinedType(method.DeclaringType))
  1228. throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
  1229. if (method.ReturnType == typeof(void))
  1230. throw ParseError(errorPos, Res.MethodIsVoid,
  1231. id, GetTypeName(method.DeclaringType));
  1232. return Expression.Call(instance, (MethodInfo)method, args);
  1233. default:
  1234. throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
  1235. id, GetTypeName(type));
  1236. }
  1237. }
  1238. else
  1239. {
  1240. MemberInfo member = FindPropertyOrField(type, id, instance == null);
  1241. if (member == null)
  1242. throw ParseError(errorPos, Res.UnknownPropertyOrField,
  1243. id, GetTypeName(type));
  1244. return member is PropertyInfo ?
  1245. Expression.Property(instance, (PropertyInfo)member) :
  1246. Expression.Field(instance, (FieldInfo)member);
  1247. }
  1248. }
  1249. static Type FindGenericType(Type generic, Type type)
  1250. {
  1251. while (type != null && type != typeof(object))
  1252. {
  1253. if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type;
  1254. if (generic.IsInterface)
  1255. {
  1256. foreach (Type intfType in type.GetInterfaces())
  1257. {
  1258. Type found = FindGenericType(generic, intfType);
  1259. if (found != null) return found;
  1260. }
  1261. }
  1262. type = type.BaseType;
  1263. }
  1264. return null;
  1265. }
  1266. Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
  1267. {
  1268. ParameterExpression outerIt = it;
  1269. ParameterExpression innerIt = Expression.Parameter(elementType, "");
  1270. it = innerIt;
  1271. Expression[] args = ParseArgumentList();
  1272. it = outerIt;
  1273. MethodBase signature;
  1274. if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
  1275. throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);
  1276. Type[] typeArgs;
  1277. if (signature.Name == "Min" || signature.Name == "Max")
  1278. {
  1279. typeArgs = new Type[] { elementType, args[0].Type };
  1280. }
  1281. else
  1282. {
  1283. typeArgs = new Type[] { elementType };
  1284. }
  1285. if (args.Length == 0)
  1286. {
  1287. args = new Expression[] { instance };
  1288. }
  1289. else
  1290. {
  1291. args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) };
  1292. }
  1293. return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
  1294. }
  1295. Expression[] ParseArgumentList()
  1296. {
  1297. ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
  1298. NextToken();
  1299. Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[0];
  1300. ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
  1301. NextToken();
  1302. return args;
  1303. }
  1304. Expression[] ParseArguments()
  1305. {
  1306. List<Expression> argList = new List<Expression>();
  1307. while (true)
  1308. {
  1309. argList.Add(ParseExpression());
  1310. if (token.id != TokenId.Comma) break;
  1311. NextToken();
  1312. }
  1313. return argList.ToArray();
  1314. }
  1315. Expression ParseElementAccess(Expression expr)
  1316. {
  1317. int errorPos = token.pos;
  1318. ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
  1319. NextToken();
  1320. Expression[] args = ParseArguments();
  1321. ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
  1322. NextToken();
  1323. if (expr.Type.IsArray)
  1324. {
  1325. if (expr.Type.GetArrayRank() != 1 || args.Length != 1)
  1326. throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
  1327. Expression index = PromoteExpression(args[0], typeof(int), true);
  1328. if (index == null)
  1329. throw ParseError(errorPos, Res.InvalidIndex);
  1330. return Expression.ArrayIndex(expr, index);
  1331. }
  1332. else
  1333. {
  1334. MethodBase mb;
  1335. switch (FindIndexer(expr.Type, args, out mb))
  1336. {
  1337. case 0:
  1338. throw ParseError(errorPos, Res.NoApplicableIndexer,
  1339. GetTypeName(expr.Type));
  1340. case 1:
  1341. return Expression.Call(expr, (MethodInfo)mb, args);
  1342. default:
  1343. throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,
  1344. GetTypeName(expr.Type));
  1345. }
  1346. }
  1347. }
  1348. static bool IsPredefinedType(Type type)
  1349. {
  1350. foreach (Type t in predefinedTypes) if (t == type) return true;
  1351. return false;
  1352. }
  1353. static bool IsNullableType(Type type)
  1354. {
  1355. return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
  1356. }
  1357. static Type GetNonNullableType(Type type)
  1358. {
  1359. return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
  1360. }
  1361. static string GetTypeName(Type type)
  1362. {
  1363. Type baseType = GetNonNullableType(type);
  1364. string s = baseType.Name;
  1365. if (type != baseType) s += '?';
  1366. return s;
  1367. }
  1368. static bool IsNumericType(Type type)
  1369. {
  1370. return GetNumericTypeKind(type) != 0;
  1371. }
  1372. static bool IsSignedIntegralType(Type type)
  1373. {
  1374. return GetNumericTypeKind(type) == 2;
  1375. }
  1376. static bool IsUnsignedIntegralType(Type type)
  1377. {
  1378. return GetNumericTypeKind(type) == 3;
  1379. }
  1380. static int GetNumericTypeKind(Type type)
  1381. {
  1382. type = GetNonNullableType(type);
  1383. if (type.IsEnum) return 0;
  1384. switch (Type.GetTypeCode(type))
  1385. {
  1386. case TypeCode.Char:
  1387. case TypeCode.Single:
  1388. case TypeCode.Double:
  1389. case TypeCode.Decimal:
  1390. return 1;
  1391. case TypeCode.SByte:
  1392. case TypeCode.Int16:
  1393. case TypeCode.Int32:
  1394. case TypeCode.Int64:
  1395. return 2;
  1396. case TypeCode.Byte:
  1397. case TypeCode.UInt16:
  1398. case TypeCode.UInt32:
  1399. case TypeCode.UInt64:
  1400. return 3;
  1401. default:
  1402. return 0;
  1403. }
  1404. }
  1405. static bool IsEnumType(Type type)
  1406. {
  1407. return GetNonNullableType(type).IsEnum;
  1408. }
  1409. void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
  1410. {
  1411. Expression[] args = new Expression[] { expr };
  1412. MethodBase method;
  1413. if (FindMethod(signatures, "F", false, args, out method) != 1)
  1414. throw ParseError(errorPos, Res.IncompatibleOperand,
  1415. opName, GetTypeName(args[0].Type));
  1416. expr = args[0];
  1417. }
  1418. void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
  1419. {
  1420. Expression[] args = new Expression[] { left, right };
  1421. MethodBase method;
  1422. if (FindMethod(signatures, "F", false, args, out method) != 1)
  1423. throw IncompatibleOperandsError(opName, left, right, errorPos);
  1424. left = args[0];
  1425. right = args[1];
  1426. }
  1427. Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
  1428. {
  1429. return ParseError(pos, Res.IncompatibleOperands,
  1430. opName, GetTypeName(left.Type), GetTypeName(right.Type));
  1431. }
  1432. MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
  1433. {
  1434. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1435. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1436. foreach (Type t in SelfAndBaseTypes(type))
  1437. {
  1438. MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
  1439. flags, Type.FilterNameIgnoreCase, memberName);
  1440. if (members.Length != 0) return members[0];
  1441. }
  1442. return null;
  1443. }
  1444. int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
  1445. {
  1446. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1447. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1448. foreach (Type t in SelfAndBaseTypes(type))
  1449. {
  1450. MemberInfo[] members = t.FindMembers(MemberTypes.Method,
  1451. flags, Type.FilterNameIgnoreCase, methodName);
  1452. int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);
  1453. if (count != 0) return count;
  1454. }
  1455. method = null;
  1456. return 0;
  1457. }
  1458. int FindIndexer(Type type, Expression[] args, out MethodBase method)
  1459. {
  1460. foreach (Type t in SelfAndBaseTypes(type))
  1461. {
  1462. MemberInfo[] members = t.GetDefaultMembers();
  1463. if (members.Length != 0)
  1464. {
  1465. IEnumerable<MethodBase> methods = members.
  1466. OfType<PropertyInfo>().
  1467. Select(p => (MethodBase)p.GetGetMethod()).
  1468. Where(m => m != null);
  1469. int count = FindBestMethod(methods, args, out method);
  1470. if (count != 0) return count;
  1471. }
  1472. }
  1473. method = null;
  1474. return 0;
  1475. }
  1476. static IEnumerable<Type> SelfAndBaseTypes(Type type)
  1477. {
  1478. if (type.IsInterface)
  1479. {
  1480. List<Type> types = new List<Type>();
  1481. AddInterface(types, type);
  1482. return types;
  1483. }
  1484. return SelfAndBaseClasses(type);
  1485. }
  1486. static IEnumerable<Type> SelfAndBaseClasses(Type type)
  1487. {
  1488. while (type != null)
  1489. {
  1490. yield return type;
  1491. type = type.BaseType;
  1492. }
  1493. }
  1494. static void AddInterface(List<Type> types, Type type)
  1495. {
  1496. if (!types.Contains(type))
  1497. {
  1498. types.Add(type);
  1499. foreach (Type t in type.GetInterfaces()) AddInterface(types, t);
  1500. }
  1501. }
  1502. class MethodData
  1503. {
  1504. public MethodBase MethodBase;
  1505. public ParameterInfo[] Parameters;
  1506. public Expression[] Args;
  1507. }
  1508. int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
  1509. {
  1510. MethodData[] applicable = methods.
  1511. Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
  1512. Where(m => IsApplicable(m, args)).
  1513. ToArray();
  1514. if (applicable.Length > 1)
  1515. {
  1516. applicable = applicable.
  1517. Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
  1518. ToArray();
  1519. }
  1520. if (applicable.Length == 1)
  1521. {
  1522. MethodData md = applicable[0];
  1523. for (int i = 0; i < args.Length; i++) args[i] = md.Args[i];
  1524. method = md.MethodBase;
  1525. }
  1526. else
  1527. {
  1528. method = null;
  1529. }
  1530. return applicable.Length;
  1531. }
  1532. bool IsApplicable(MethodData method, Expression[] args)
  1533. {
  1534. if (method.Parameters.Length != args.Length) return false;
  1535. Expression[] promotedArgs = new Expression[args.Length];
  1536. for (int i = 0; i < args.Length; i++)
  1537. {
  1538. ParameterInfo pi = method.Parameters[i];
  1539. if (pi.IsOut) return false;
  1540. Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
  1541. if (promoted == null) return false;
  1542. promotedArgs[i] = promoted;
  1543. }
  1544. method.Args = promotedArgs;
  1545. return true;
  1546. }
  1547. Expression PromoteExpression(Expression expr, Type type, bool exact)
  1548. {
  1549. if (expr.Type == type) return expr;
  1550. if (expr is ConstantExpression)
  1551. {
  1552. ConstantExpression ce = (ConstantExpression)expr;
  1553. if (ce == nullLiteral)
  1554. {
  1555. if (!type.IsValueType || IsNullableType(type))
  1556. return Expression.Constant(null, type);
  1557. }
  1558. else
  1559. {
  1560. string text;
  1561. if (literals.TryGetValue(ce, out text))
  1562. {
  1563. Type target = GetNonNullableType(type);
  1564. Object value = null;
  1565. switch (Type.GetTypeCode(ce.Type))
  1566. {
  1567. case TypeCode.Int32:
  1568. case TypeCode.UInt32:
  1569. case TypeCode.Int64:
  1570. case TypeCode.UInt64:
  1571. value = ParseNumber(text, target);
  1572. break;
  1573. case TypeCode.Double:
  1574. if (target == typeof(decimal)) value = ParseNumber(text, target);
  1575. break;
  1576. case TypeCode.String:
  1577. value = ParseEnum(text, target);
  1578. break;
  1579. }
  1580. if (value != null)
  1581. return Expression.Constant(value, type);
  1582. }
  1583. }
  1584. }
  1585. if (IsCompatibleWith(expr.Type, type))
  1586. {
  1587. if (type.IsValueType || exact) return Expression.Convert(expr, type);
  1588. return expr;
  1589. }
  1590. return null;
  1591. }
  1592. static object ParseNumber(string text, Type type)
  1593. {
  1594. switch (Type.GetTypeCode(GetNonNullableType(type)))
  1595. {
  1596. case TypeCode.SByte:
  1597. sbyte sb;
  1598. if (sbyte.TryParse(text, out sb)) return sb;
  1599. break;
  1600. case TypeCode.Byte:
  1601. byte b;
  1602. if (byte.TryParse(text, out b)) return b;
  1603. break;
  1604. case TypeCode.Int16:
  1605. short s;
  1606. if (short.TryParse(text, out s)) return s;
  1607. break;
  1608. case TypeCode.UInt16:
  1609. ushort us;
  1610. if (ushort.TryParse(text, out us)) return us;
  1611. break;
  1612. case TypeCode.Int32:
  1613. int i;
  1614. if (int.TryParse(text, out i)) return i;
  1615. break;
  1616. case TypeCode.UInt32:
  1617. uint ui;
  1618. if (uint.TryParse(text, out ui)) return ui;
  1619. break;
  1620. case TypeCode.Int64:
  1621. long l;
  1622. if (long.TryParse(text, out l)) return l;
  1623. break;
  1624. case TypeCode.UInt64:
  1625. ulong ul;
  1626. if (ulong.TryParse(text, out ul)) return ul;
  1627. break;
  1628. case TypeCode.Single:
  1629. float f;
  1630. if (float.TryParse(text, out f)) return f;
  1631. break;
  1632. case TypeCode.Double:
  1633. double d;
  1634. if (double.TryParse(text, out d)) return d;
  1635. break;
  1636. case TypeCode.Decimal:
  1637. decimal e;
  1638. if (decimal.TryParse(text, out e)) return e;
  1639. break;
  1640. }
  1641. return null;
  1642. }
  1643. static object ParseEnum(string name, Type type)
  1644. {
  1645. if (type.IsEnum)
  1646. {
  1647. MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
  1648. BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
  1649. Type.FilterNameIgnoreCase, name);
  1650. if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null);
  1651. }
  1652. return null;
  1653. }
  1654. static bool IsCompatibleWith(Type source, Type target)
  1655. {
  1656. if (source == target) return true;
  1657. if (!target.IsValueType) return target.IsAssignableFrom(source);
  1658. Type st = GetNonNullableType(source);
  1659. Type tt = GetNonNullableType(target);
  1660. if (st != source && tt == target) return false;
  1661. TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);
  1662. TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);
  1663. switch (sc)
  1664. {
  1665. case TypeCode.SByte:
  1666. switch (tc)
  1667. {
  1668. case TypeCode.SByte:
  1669. case TypeCode.Int16:
  1670. case TypeCode.Int32:
  1671. case TypeCode.Int64:
  1672. case TypeCode.Single:
  1673. case TypeCode.Double:
  1674. case TypeCode.Decimal:
  1675. return true;
  1676. }
  1677. break;
  1678. case TypeCode.Byte:
  1679. switch (tc)
  1680. {
  1681. case TypeCode.Byte:
  1682. case TypeCode.Int16:
  1683. case TypeCode.UInt16:
  1684. case TypeCode.Int32:
  1685. case TypeCode.UInt32:
  1686. case TypeCode.Int64:
  1687. case TypeCode.UInt64:
  1688. case TypeCode.Single:
  1689. case TypeCode.Double:
  1690. case TypeCode.Decimal:
  1691. return true;
  1692. }
  1693. break;
  1694. case TypeCode.Int16:
  1695. switch (tc)
  1696. {
  1697. case TypeCode.Int16:
  1698. case TypeCode.Int32:
  1699. case TypeCode.Int64:
  1700. case TypeCode.Single:
  1701. case TypeCode.Double:
  1702. case TypeCode.Decimal:
  1703. return true;
  1704. }
  1705. break;
  1706. case TypeCode.UInt16:
  1707. switch (tc)
  1708. {
  1709. case TypeCode.UInt16:
  1710. case TypeCode.Int32:
  1711. case TypeCode.UInt32:
  1712. case TypeCode.Int64:
  1713. case TypeCode.UInt64:
  1714. case TypeCode.Single:
  1715. case TypeCode.Double:
  1716. case TypeCode.Decimal:
  1717. return true;
  1718. }
  1719. break;
  1720. case TypeCode.Int32:
  1721. switch (tc)
  1722. {
  1723. case TypeCode.Int32:
  1724. case TypeCode.Int64:
  1725. case TypeCode.Single:
  1726. case TypeCode.Double:
  1727. case TypeCode.Decimal:
  1728. return true;
  1729. }
  1730. break;
  1731. case TypeCode.UInt32:
  1732. switch (tc)
  1733. {
  1734. case TypeCode.UInt32:
  1735. case TypeCode.Int64:
  1736. case TypeCode.UInt64:
  1737. case TypeCode.Single:
  1738. case TypeCode.Double:
  1739. case TypeCode.Decimal:
  1740. return true;
  1741. }
  1742. break;
  1743. case TypeCode.Int64:
  1744. switch (tc)
  1745. {
  1746. case TypeCode.Int64:
  1747. case TypeCode.Single:
  1748. case TypeCode.Double:
  1749. case TypeCode.Decimal:
  1750. return true;
  1751. }
  1752. break;
  1753. case TypeCode.UInt64:
  1754. switch (tc)
  1755. {
  1756. case TypeCode.UInt64:
  1757. case TypeCode.Single:
  1758. case TypeCode.Double:
  1759. case TypeCode.Decimal:
  1760. return true;
  1761. }
  1762. break;
  1763. case TypeCode.Single:
  1764. switch (tc)
  1765. {
  1766. case TypeCode.Single:
  1767. case TypeCode.Double:
  1768. return true;
  1769. }
  1770. break;
  1771. default:
  1772. if (st == tt) return true;
  1773. break;
  1774. }
  1775. return false;
  1776. }
  1777. static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
  1778. {
  1779. bool better = false;
  1780. for (int i = 0; i < args.Length; i++)
  1781. {
  1782. int c = CompareConversions(args[i].Type,
  1783. m1.Parameters[i].ParameterType,
  1784. m2.Parameters[i].ParameterType);
  1785. if (c < 0) return false;
  1786. if (c > 0) better = true;
  1787. }
  1788. return better;
  1789. }
  1790. // Return 1 if s -> t1 is a better conversion than s -> t2
  1791. // Return -1 if s -> t2 is a better conversion than s -> t1
  1792. // Return 0 if neither conversion is better
  1793. static int CompareConversions(Type s, Type t1, Type t2)
  1794. {
  1795. if (t1 == t2) return 0;
  1796. if (s == t1) return 1;
  1797. if (s == t2) return -1;
  1798. bool t1t2 = IsCompatibleWith(t1, t2);
  1799. bool t2t1 = IsCompatibleWith(t2, t1);
  1800. if (t1t2 && !t2t1) return 1;
  1801. if (t2t1 && !t1t2) return -1;
  1802. if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1;
  1803. if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1;
  1804. return 0;
  1805. }
  1806. Expression GenerateEqual(Expression left, Expression right)
  1807. {
  1808. return Expression.Equal(left, right);
  1809. }
  1810. Expression GenerateNotEqual(Expression left, Expression right)
  1811. {
  1812. return Expression.NotEqual(left, right);
  1813. }
  1814. Expression GenerateGreaterThan(Expression left, Expression right)
  1815. {
  1816. if (left.Type == typeof(string))
  1817. {
  1818. return Expression.GreaterThan(
  1819. GenerateStaticMethodCall("Compare", left, right),
  1820. Expression.Constant(0)
  1821. );
  1822. }
  1823. return Expression.GreaterThan(left, right);
  1824. }
  1825. Expression GenerateGreaterThanEqual(Expression left, Expression right)
  1826. {
  1827. if (left.Type == typeof(string))
  1828. {
  1829. return Expression.GreaterThanOrEqual(
  1830. GenerateStaticMethodCall("Compare", left, right),
  1831. Expression.Constant(0)
  1832. );
  1833. }
  1834. return Expression.GreaterThanOrEqual(left, right);
  1835. }
  1836. Expression GenerateLessThan(Expression left, Expression right)
  1837. {
  1838. if (left.Type == typeof(string))
  1839. {
  1840. return Expression.LessThan(
  1841. GenerateStaticMethodCall("Compare", left, right),
  1842. Expression.Constant(0)
  1843. );
  1844. }
  1845. return Expression.LessThan(left, right);
  1846. }
  1847. Expression GenerateLessThanEqual(Expression left, Expression right)
  1848. {
  1849. if (left.Type == typeof(string))
  1850. {
  1851. return Expression.LessThanOrEqual(
  1852. GenerateStaticMethodCall("Compare", left, right),
  1853. Expression.Constant(0)
  1854. );
  1855. }
  1856. return Expression.LessThanOrEqual(left, right);
  1857. }
  1858. Expression GenerateAdd(Expression left, Expression right)
  1859. {
  1860. if (left.Type == typeof(string) && right.Type == typeof(string))
  1861. {
  1862. return GenerateStaticMethodCall("Concat", left, right);
  1863. }
  1864. return Expression.Add(left, right);
  1865. }
  1866. Expression GenerateSubtract(Expression left, Expression right)
  1867. {
  1868. return Expression.Subtract(left, right);
  1869. }
  1870. Expression GenerateStringConcat(Expression left, Expression right)
  1871. {
  1872. return Expression.Call(
  1873. null,
  1874. typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
  1875. new[] { left, right });
  1876. }
  1877. MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
  1878. {
  1879. return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
  1880. }
  1881. Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
  1882. {
  1883. return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
  1884. }
  1885. void SetTextPos(int pos)
  1886. {
  1887. textPos = pos;
  1888. ch = textPos < textLen ? text[textPos] : '\0';
  1889. }
  1890. void NextChar()
  1891. {
  1892. if (textPos < textLen) textPos++;
  1893. ch = textPos < textLen ? text[textPos] : '\0';
  1894. }
  1895. void NextToken()
  1896. {
  1897. while (Char.IsWhiteSpace(ch)) NextChar();
  1898. TokenId t;
  1899. int tokenPos = textPos;
  1900. switch (ch)
  1901. {
  1902. case '!':
  1903. NextChar();
  1904. if (ch == '=')
  1905. {
  1906. NextChar();
  1907. t = TokenId.ExclamationEqual;
  1908. }
  1909. else
  1910. {
  1911. t = TokenId.Exclamation;
  1912. }
  1913. break;
  1914. case '%':
  1915. NextChar();
  1916. t = TokenId.Percent;
  1917. break;
  1918. case '&':
  1919. NextChar();
  1920. if (ch == '&')
  1921. {
  1922. NextChar();
  1923. t = TokenId.DoubleAmphersand;
  1924. }
  1925. else
  1926. {
  1927. t = TokenId.Amphersand;
  1928. }
  1929. break;
  1930. case '(':
  1931. NextChar();
  1932. t = TokenId.OpenParen;
  1933. break;
  1934. case ')':
  1935. NextChar();
  1936. t = TokenId.CloseParen;
  1937. break;
  1938. case '*':
  1939. NextChar();
  1940. t = TokenId.Asterisk;
  1941. break;
  1942. case '+':
  1943. NextChar();
  1944. t = TokenId.Plus;
  1945. break;
  1946. case ',':
  1947. NextChar();
  1948. t = TokenId.Comma;
  1949. break;
  1950. case '-':
  1951. NextChar();
  1952. t = TokenId.Minus;
  1953. break;
  1954. case '.':
  1955. NextChar();
  1956. t = TokenId.Dot;
  1957. break;
  1958. case '/':
  1959. NextChar();
  1960. t = TokenId.Slash;
  1961. break;
  1962. case ':':
  1963. NextChar();
  1964. t = TokenId.Colon;
  1965. break;
  1966. case '<':
  1967. NextChar();
  1968. if (ch == '=')
  1969. {
  1970. NextChar();
  1971. t = TokenId.LessThanEqual;
  1972. }
  1973. else if (ch == '>')
  1974. {
  1975. NextChar();
  1976. t = TokenId.LessGreater;
  1977. }
  1978. else
  1979. {
  1980. t = TokenId.LessThan;
  1981. }
  1982. break;
  1983. case '=':
  1984. NextChar();
  1985. if (ch == '=')
  1986. {
  1987. NextChar();
  1988. t = TokenId.DoubleEqual;
  1989. }
  1990. else
  1991. {
  1992. t = TokenId.Equal;
  1993. }
  1994. break;
  1995. case '>':
  1996. NextChar();
  1997. if (ch == '=')
  1998. {
  1999. NextChar();
  2000. t = TokenId.GreaterThanEqual;
  2001. }
  2002. else
  2003. {
  2004. t = TokenId.GreaterThan;
  2005. }
  2006. break;
  2007. case '?':
  2008. NextChar();
  2009. t = TokenId.Question;
  2010. break;
  2011. case '[':
  2012. NextChar();
  2013. t = TokenId.OpenBracket;
  2014. break;
  2015. case ']':
  2016. NextChar();
  2017. t = TokenId.CloseBracket;
  2018. break;
  2019. case '|':
  2020. NextChar();
  2021. if (ch == '|')
  2022. {
  2023. NextChar();
  2024. t = TokenId.DoubleBar;
  2025. }
  2026. else
  2027. {
  2028. t = TokenId.Bar;
  2029. }
  2030. break;
  2031. case '"':
  2032. case '\'':
  2033. char quote = ch;
  2034. do
  2035. {
  2036. NextChar();
  2037. while (textPos < textLen && ch != quote) NextChar();
  2038. if (textPos == textLen)
  2039. throw ParseError(textPos, Res.UnterminatedStringLiteral);
  2040. NextChar();
  2041. } while (ch == quote);
  2042. t = TokenId.StringLiteral;
  2043. break;
  2044. default:
  2045. if (Char.IsLetter(ch) || ch == '@' || ch == '_')
  2046. {
  2047. do
  2048. {
  2049. NextChar();
  2050. } while (Char.IsLetterOrDigit(ch) || ch == '_');
  2051. t = TokenId.Identifier;
  2052. break;
  2053. }
  2054. if (Char.IsDigit(ch))
  2055. {
  2056. t = TokenId.IntegerLiteral;
  2057. do
  2058. {
  2059. NextChar();
  2060. } while (Char.IsDigit(ch));
  2061. if (ch == '.')
  2062. {
  2063. t = TokenId.RealLiteral;
  2064. NextChar();
  2065. ValidateDigit();
  2066. do
  2067. {
  2068. NextChar();
  2069. } while (Char.IsDigit(ch));
  2070. }
  2071. if (ch == 'E' || ch == 'e')
  2072. {
  2073. t = TokenId.RealLiteral;
  2074. NextChar();
  2075. if (ch == '+' || ch == '-') NextChar();
  2076. ValidateDigit();
  2077. do
  2078. {
  2079. NextChar();
  2080. } while (Char.IsDigit(ch));
  2081. }
  2082. if (ch == 'F' || ch == 'f') NextChar();
  2083. break;
  2084. }
  2085. if (textPos == textLen)
  2086. {
  2087. t = TokenId.End;
  2088. break;
  2089. }
  2090. throw ParseError(textPos, Res.InvalidCharacter, ch);
  2091. }
  2092. token.id = t;
  2093. token.text = text.Substring(tokenPos, textPos - tokenPos);
  2094. token.pos = tokenPos;
  2095. }
  2096. bool TokenIdentifierIs(string id)
  2097. {
  2098. return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);
  2099. }
  2100. string GetIdentifier()
  2101. {
  2102. ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
  2103. string id = token.text;
  2104. if (id.Length > 1 && id[0] == '@') id = id.Substring(1);
  2105. return id;
  2106. }
  2107. void ValidateDigit()
  2108. {
  2109. if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);
  2110. }
  2111. void ValidateToken(TokenId t, string errorMessage)
  2112. {
  2113. if (token.id != t) throw ParseError(errorMessage);
  2114. }
  2115. void ValidateToken(TokenId t)
  2116. {
  2117. if (token.id != t) throw ParseError(Res.SyntaxError);
  2118. }
  2119. Exception ParseError(string format, params object[] args)
  2120. {
  2121. return ParseError(token.pos, format, args);
  2122. }
  2123. Exception ParseError(int pos, string format, params object[] args)
  2124. {
  2125. return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);
  2126. }
  2127. static Dictionary<string, object> CreateKeywords()
  2128. {
  2129. Dictionary<string, object> d = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  2130. d.Add("true", trueLiteral);
  2131. d.Add("false", falseLiteral);
  2132. d.Add("null", nullLiteral);
  2133. d.Add(keywordIt, keywordIt);
  2134. d.Add(keywordIif, keywordIif);
  2135. d.Add(keywordNew, keywordNew);
  2136. foreach (Type type in predefinedTypes) d.Add(type.Name, type);
  2137. return d;
  2138. }
  2139. }
  2140. static class Res
  2141. {
  2142. public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once";
  2143. public const string ExpressionTypeMismatch = "Expression of type '{0}' expected";
  2144. public const string ExpressionExpected = "Expression expected";
  2145. public const string InvalidCharacterLiteral = "Character literal must contain exactly one character";
  2146. public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'";
  2147. public const string InvalidRealLiteral = "Invalid real literal '{0}'";
  2148. public const string UnknownIdentifier = "Unknown identifier '{0}'";
  2149. public const string NoItInScope = "No 'it' is in scope";
  2150. public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments";
  2151. public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'";
  2152. public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other";
  2153. public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other";
  2154. public const string MissingAsClause = "Expression is missing an 'as' clause";
  2155. public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression";
  2156. public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form";
  2157. public const string NoMatchingConstructor = "No matching constructor in type '{0}'";
  2158. public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor";
  2159. public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'";
  2160. public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'";
  2161. public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible";
  2162. public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value";
  2163. public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'";
  2164. public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'";
  2165. public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists";
  2166. public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported";
  2167. public const string InvalidIndex = "Array index must be an integer expression";
  2168. public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'";
  2169. public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'";
  2170. public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'";
  2171. public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'";
  2172. public const string UnterminatedStringLiteral = "Unterminated string literal";
  2173. public const string InvalidCharacter = "Syntax error '{0}'";
  2174. public const string DigitExpected = "Digit expected";
  2175. public const string SyntaxError = "Syntax error";
  2176. public const string TokenExpected = "{0} expected";
  2177. public const string ParseExceptionFormat = "{0} (at index {1})";
  2178. public const string ColonExpected = "':' expected";
  2179. public const string OpenParenExpected = "'(' expected";
  2180. public const string CloseParenOrOperatorExpected = "')' or operator expected";
  2181. public const string CloseParenOrCommaExpected = "')' or ',' expected";
  2182. public const string DotOrOpenParenExpected = "'.' or '(' expected";
  2183. public const string OpenBracketExpected = "'[' expected";
  2184. public const string CloseBracketOrCommaExpected = "']' or ',' expected";
  2185. public const string IdentifierExpected = "Identifier expected";
  2186. }
  2187. }