PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.ApplicationServer.Http/Microsoft/ApplicationServer/Query/DynamicQueryable.cs

#
C# | 2292 lines | 2129 code | 130 blank | 33 comment | 470 complexity | f152c28c7f61f7927d0c126ac0352ad7 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. // <copyright>
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // </copyright>
  4. namespace Microsoft.ApplicationServer.Query
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Linq;
  10. using System.Linq.Expressions;
  11. using System.Reflection;
  12. using Microsoft.ApplicationServer.Http;
  13. internal static class DynamicQueryable
  14. {
  15. public static IQueryable Where(this IQueryable source, string predicate, QueryResolver queryResolver)
  16. {
  17. if (source == null)
  18. throw new ArgumentNullException("source");
  19. if (predicate == null)
  20. throw new ArgumentNullException("predicate");
  21. LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, queryResolver);
  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 OrderBy(this IQueryable source, string ordering, QueryResolver queryResolver)
  29. {
  30. if (source == null)
  31. throw new ArgumentNullException("source");
  32. if (ordering == null)
  33. throw new ArgumentNullException("ordering");
  34. ParameterExpression[] parameters = new ParameterExpression[] {
  35. Expression.Parameter(source.ElementType, "") };
  36. ExpressionParser parser = new ExpressionParser(parameters, ordering, queryResolver);
  37. IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
  38. Expression queryExpr = source.Expression;
  39. string methodAsc = "OrderBy";
  40. string methodDesc = "OrderByDescending";
  41. foreach (DynamicOrdering o in orderings)
  42. {
  43. queryExpr = Expression.Call(
  44. typeof(Queryable), o.Ascending ? methodAsc : methodDesc,
  45. new Type[] { source.ElementType, o.Selector.Type },
  46. queryExpr, Expression.Quote(DynamicExpression.Lambda(o.Selector, parameters)));
  47. methodAsc = "ThenBy";
  48. methodDesc = "ThenByDescending";
  49. }
  50. return source.Provider.CreateQuery(queryExpr);
  51. }
  52. public static IQueryable Take(this IQueryable source, int count)
  53. {
  54. if (source == null)
  55. throw new ArgumentNullException("source");
  56. return source.Provider.CreateQuery(
  57. Expression.Call(
  58. typeof(Queryable), "Take",
  59. new Type[] { source.ElementType },
  60. source.Expression, Expression.Constant(count)));
  61. }
  62. public static IQueryable Skip(this IQueryable source, int count)
  63. {
  64. if (source == null)
  65. throw new ArgumentNullException("source");
  66. return source.Provider.CreateQuery(
  67. Expression.Call(
  68. typeof(Queryable), "Skip",
  69. new Type[] { source.ElementType },
  70. source.Expression, Expression.Constant(count)));
  71. }
  72. }
  73. internal static class DynamicExpression
  74. {
  75. static readonly Type[] funcTypes = new Type[] {
  76. typeof(Func<>),
  77. typeof(Func<,>),
  78. typeof(Func<,,>),
  79. typeof(Func<,,,>),
  80. typeof(Func<,,,,>)
  81. };
  82. public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, QueryResolver queryResolver)
  83. {
  84. return ParseLambda(new ParameterExpression[] { Expression.Parameter(itType, "") }, resultType, expression, queryResolver);
  85. }
  86. public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, QueryResolver queryResolver)
  87. {
  88. ExpressionParser parser = new ExpressionParser(parameters, expression, queryResolver);
  89. return Lambda(parser.Parse(resultType), parameters);
  90. }
  91. public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters)
  92. {
  93. int paramCount = parameters == null ? 0 : parameters.Length;
  94. Type[] typeArgs = new Type[paramCount + 1];
  95. for (int i = 0; i < paramCount; i++)
  96. typeArgs[i] = parameters[i].Type;
  97. typeArgs[paramCount] = body.Type;
  98. return Expression.Lambda(GetFuncType(typeArgs), body, parameters);
  99. }
  100. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly", Justification = "Arguments are provided internally by the parser's ParserLambda methods.")]
  101. public static Type GetFuncType(params Type[] typeArgs)
  102. {
  103. if (typeArgs == null || typeArgs.Length < 1 || typeArgs.Length > 5)
  104. throw new ArgumentException();
  105. return funcTypes[typeArgs.Length - 1].MakeGenericType(typeArgs);
  106. }
  107. }
  108. internal class DynamicOrdering
  109. {
  110. public Expression Selector;
  111. public bool Ascending;
  112. }
  113. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "Exception is intended to only be used by the dynamic parser.")]
  114. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic", Justification = "Exception is intended to only be used by the dynamic parser.")]
  115. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "Exception is intended to only be used by the dynamic parser.")]
  116. internal class ParseException : Exception
  117. {
  118. public ParseException(string message, int position)
  119. : base(string.Format(CultureInfo.InvariantCulture, SR.ParseExceptionFormat(message, position)))
  120. {
  121. }
  122. }
  123. internal class ExpressionParser
  124. {
  125. struct Token
  126. {
  127. public TokenId id;
  128. public string text;
  129. public int pos;
  130. }
  131. enum TokenId
  132. {
  133. Unknown,
  134. End,
  135. Identifier,
  136. StringLiteral,
  137. IntegerLiteral,
  138. RealLiteral,
  139. Exclamation,
  140. Percent,
  141. Amphersand,
  142. OpenParen,
  143. CloseParen,
  144. Asterisk,
  145. Plus,
  146. Comma,
  147. Minus,
  148. Dot,
  149. Slash,
  150. Colon,
  151. LessThan,
  152. Equal,
  153. GreaterThan,
  154. Question,
  155. OpenBracket,
  156. CloseBracket,
  157. Bar,
  158. ExclamationEqual,
  159. DoubleAmphersand,
  160. LessThanEqual,
  161. LessGreater,
  162. DoubleEqual,
  163. GreaterThanEqual,
  164. DoubleBar
  165. }
  166. internal class MappedMemberInfo
  167. {
  168. public MappedMemberInfo(Type mappedType, string memberName, bool isStatic, bool isMethod)
  169. {
  170. MappedType = mappedType;
  171. MemberName = memberName;
  172. IsStatic = isStatic;
  173. IsMethod = isMethod;
  174. }
  175. public Type MappedType { get; private set; }
  176. public string MemberName { get; private set; }
  177. public bool IsStatic { get; private set; }
  178. public bool IsMethod { get; private set; }
  179. }
  180. interface ILogicalSignatures
  181. {
  182. void F(bool x, bool y);
  183. void F(bool? x, bool? y);
  184. }
  185. interface IArithmeticSignatures
  186. {
  187. void F(int x, int y);
  188. void F(uint x, uint y);
  189. void F(long x, long y);
  190. void F(ulong x, ulong y);
  191. void F(float x, float y);
  192. void F(double x, double y);
  193. void F(decimal x, decimal y);
  194. void F(int? x, int? y);
  195. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  196. void F(uint? x, uint? y);
  197. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  198. void F(long? x, long? y);
  199. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  200. void F(ulong? x, ulong? y);
  201. void F(float? x, float? y);
  202. void F(double? x, double? y);
  203. void F(decimal? x, decimal? y);
  204. }
  205. interface IRelationalSignatures : IArithmeticSignatures
  206. {
  207. void F(string x, string y);
  208. void F(char x, char y);
  209. void F(DateTime x, DateTime y);
  210. void F(TimeSpan x, TimeSpan y);
  211. void F(char? x, char? y);
  212. void F(DateTime? x, DateTime? y);
  213. void F(TimeSpan? x, TimeSpan? y);
  214. void F(DateTimeOffset x, DateTimeOffset y);
  215. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  216. void F(DateTimeOffset? x, DateTimeOffset? y);
  217. }
  218. interface IEqualitySignatures : IRelationalSignatures
  219. {
  220. void F(bool x, bool y);
  221. void F(bool? x, bool? y);
  222. void F(Guid x, Guid y);
  223. void F(Guid? x, Guid? y);
  224. }
  225. interface IAddSignatures : IArithmeticSignatures
  226. {
  227. void F(DateTime x, TimeSpan y);
  228. void F(TimeSpan x, TimeSpan y);
  229. void F(DateTime? x, TimeSpan? y);
  230. void F(TimeSpan? x, TimeSpan? y);
  231. void F(DateTimeOffset x, TimeSpan y);
  232. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  233. void F(DateTimeOffset? x, TimeSpan? y);
  234. }
  235. interface ISubtractSignatures : IAddSignatures
  236. {
  237. void F(DateTime x, DateTime y);
  238. void F(DateTime? x, DateTime? y);
  239. void F(DateTimeOffset x, DateTimeOffset y);
  240. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.MSInternal", "CA908:AvoidTypesThatRequireJitCompilationInPrecompiledAssemblies", Justification = "Legacy code.")]
  241. void F(DateTimeOffset? x, DateTimeOffset? y);
  242. }
  243. interface INegationSignatures
  244. {
  245. void F(int x);
  246. void F(long x);
  247. void F(float x);
  248. void F(double x);
  249. void F(decimal x);
  250. void F(int? x);
  251. void F(long? x);
  252. void F(float? x);
  253. void F(double? x);
  254. void F(decimal? x);
  255. }
  256. interface INotSignatures
  257. {
  258. void F(bool x);
  259. void F(bool? x);
  260. }
  261. interface IEnumerableSignatures
  262. {
  263. void Where(bool predicate);
  264. void Any();
  265. void Any(bool predicate);
  266. void All(bool predicate);
  267. void Count();
  268. void Count(bool predicate);
  269. void Min(object selector);
  270. void Max(object selector);
  271. void Sum(int selector);
  272. void Sum(int? selector);
  273. void Sum(long selector);
  274. void Sum(long? selector);
  275. void Sum(float selector);
  276. void Sum(float? selector);
  277. void Sum(double selector);
  278. void Sum(double? selector);
  279. void Sum(decimal selector);
  280. void Sum(decimal? selector);
  281. void Average(int selector);
  282. void Average(int? selector);
  283. void Average(long selector);
  284. void Average(long? selector);
  285. void Average(float selector);
  286. void Average(float? selector);
  287. void Average(double selector);
  288. void Average(double? selector);
  289. void Average(decimal selector);
  290. void Average(decimal? selector);
  291. }
  292. static readonly Type[] predefinedTypes = {
  293. typeof(Object),
  294. typeof(Boolean),
  295. typeof(Char),
  296. typeof(String),
  297. typeof(SByte),
  298. typeof(Byte),
  299. typeof(Int16),
  300. typeof(UInt16),
  301. typeof(Int32),
  302. typeof(UInt32),
  303. typeof(Int64),
  304. typeof(UInt64),
  305. typeof(Single),
  306. typeof(Double),
  307. typeof(Decimal),
  308. typeof(DateTime),
  309. typeof(DateTimeOffset),
  310. typeof(TimeSpan),
  311. typeof(Guid),
  312. typeof(Math),
  313. typeof(Convert),
  314. typeof(StringComparison),
  315. typeof(Uri)
  316. };
  317. static readonly Expression trueLiteral = Expression.Constant(true);
  318. static readonly Expression falseLiteral = Expression.Constant(false);
  319. static readonly Expression nullLiteral = Expression.Constant(null);
  320. const string keywordIt = "it";
  321. const string keywordIif = "iif";
  322. static Dictionary<string, object> keywords;
  323. Dictionary<string, object> symbols;
  324. Dictionary<Expression, string> literals;
  325. ParameterExpression it;
  326. string text;
  327. int textPos;
  328. int textLen;
  329. char ch;
  330. Token token;
  331. QueryResolver queryResolver;
  332. public ExpressionParser(ParameterExpression[] parameters, string expression, QueryResolver queryResolver)
  333. {
  334. if (expression == null)
  335. throw new ArgumentNullException("expression");
  336. if (keywords == null)
  337. keywords = CreateKeywords();
  338. this.queryResolver = queryResolver;
  339. symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  340. literals = new Dictionary<Expression, string>();
  341. if (parameters != null)
  342. ProcessParameters(parameters);
  343. text = expression;
  344. textLen = text.Length;
  345. SetTextPos(0);
  346. NextToken();
  347. }
  348. void ProcessParameters(ParameterExpression[] parameters)
  349. {
  350. foreach (ParameterExpression pe in parameters)
  351. if (!String.IsNullOrEmpty(pe.Name))
  352. AddSymbol(pe.Name, pe);
  353. if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
  354. it = parameters[0];
  355. }
  356. void AddSymbol(string name, object value)
  357. {
  358. if (symbols.ContainsKey(name))
  359. throw ParseError(SR.DuplicateIdentifier(name));
  360. symbols.Add(name, value);
  361. }
  362. public Expression Parse(Type resultType)
  363. {
  364. int exprPos = token.pos;
  365. Expression expr = ParseExpression();
  366. if (resultType != null)
  367. if ((expr = PromoteExpression(expr, resultType, true)) == null)
  368. throw ParseError(exprPos, SR.ExpressionTypeMismatch(GetTypeName(resultType)));
  369. ValidateToken(TokenId.End, SR.SyntaxError);
  370. return expr;
  371. }
  372. #pragma warning disable 0219
  373. public IEnumerable<DynamicOrdering> ParseOrdering()
  374. {
  375. List<DynamicOrdering> orderings = new List<DynamicOrdering>();
  376. while (true)
  377. {
  378. Expression expr = ParseExpression();
  379. bool ascending = true;
  380. if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
  381. {
  382. NextToken();
  383. }
  384. else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
  385. {
  386. NextToken();
  387. ascending = false;
  388. }
  389. orderings.Add(new DynamicOrdering
  390. {
  391. Selector = expr,
  392. Ascending = ascending
  393. });
  394. if (token.id != TokenId.Comma)
  395. break;
  396. NextToken();
  397. }
  398. ValidateToken(TokenId.End, SR.SyntaxError);
  399. return orderings;
  400. }
  401. #pragma warning restore 0219
  402. // ?: operator
  403. Expression ParseExpression()
  404. {
  405. int errorPos = token.pos;
  406. Expression expr = ParseLogicalOr();
  407. if (token.id == TokenId.Question)
  408. {
  409. NextToken();
  410. Expression expr1 = ParseExpression();
  411. ValidateToken(TokenId.Colon, SR.ColonExpected);
  412. NextToken();
  413. Expression expr2 = ParseExpression();
  414. expr = GenerateConditional(expr, expr1, expr2, errorPos);
  415. }
  416. return expr;
  417. }
  418. // ||, or operator
  419. Expression ParseLogicalOr()
  420. {
  421. Expression left = ParseLogicalAnd();
  422. while (token.id == TokenId.DoubleBar || TokenIdentifierIs("or"))
  423. {
  424. Token op = token;
  425. NextToken();
  426. Expression right = ParseLogicalAnd();
  427. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  428. left = Expression.OrElse(left, right);
  429. }
  430. return left;
  431. }
  432. // &&, and operator
  433. Expression ParseLogicalAnd()
  434. {
  435. Expression left = ParseComparison();
  436. while (token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
  437. {
  438. Token op = token;
  439. NextToken();
  440. Expression right = ParseComparison();
  441. CheckAndPromoteOperands(typeof(ILogicalSignatures), op.text, ref left, ref right, op.pos);
  442. left = Expression.AndAlso(left, right);
  443. }
  444. return left;
  445. }
  446. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Legacy code.")]
  447. // =, ==, !=, <>, >, >=, <, <= operators
  448. Expression ParseComparison()
  449. {
  450. Expression left = ParseAdditive();
  451. while (token.id == TokenId.Equal || token.id == TokenId.DoubleEqual ||
  452. token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater ||
  453. token.id == TokenId.GreaterThan || token.id == TokenId.GreaterThanEqual ||
  454. token.id == TokenId.LessThan || token.id == TokenId.LessThanEqual)
  455. {
  456. Token op = token;
  457. NextToken();
  458. Expression right = ParseAdditive();
  459. bool isEquality = op.id == TokenId.Equal || op.id == TokenId.DoubleEqual ||
  460. op.id == TokenId.ExclamationEqual || op.id == TokenId.LessGreater;
  461. if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)
  462. {
  463. if (left.Type != right.Type)
  464. {
  465. if (left.Type.IsAssignableFrom(right.Type))
  466. {
  467. right = Expression.Convert(right, left.Type);
  468. }
  469. else if (right.Type.IsAssignableFrom(left.Type))
  470. {
  471. left = Expression.Convert(left, right.Type);
  472. }
  473. else
  474. {
  475. throw IncompatibleOperandsError(op.text, left, right, op.pos);
  476. }
  477. }
  478. }
  479. else if (IsEnumType(left.Type) || IsEnumType(right.Type))
  480. {
  481. // convert enum expressions to their underlying values for comparison
  482. left = ConvertEnumExpression(left, right);
  483. right = ConvertEnumExpression(right, left);
  484. CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
  485. op.text, ref left, ref right, op.pos);
  486. }
  487. else
  488. {
  489. CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
  490. op.text, ref left, ref right, op.pos);
  491. }
  492. switch (op.id)
  493. {
  494. case TokenId.Equal:
  495. case TokenId.DoubleEqual:
  496. left = GenerateEqual(left, right);
  497. break;
  498. case TokenId.ExclamationEqual:
  499. case TokenId.LessGreater:
  500. left = GenerateNotEqual(left, right);
  501. break;
  502. case TokenId.GreaterThan:
  503. left = GenerateGreaterThan(left, right);
  504. break;
  505. case TokenId.GreaterThanEqual:
  506. left = GenerateGreaterThanEqual(left, right);
  507. break;
  508. case TokenId.LessThan:
  509. left = GenerateLessThan(left, right);
  510. break;
  511. case TokenId.LessThanEqual:
  512. left = GenerateLessThanEqual(left, right);
  513. break;
  514. }
  515. }
  516. return left;
  517. }
  518. /// <summary>
  519. /// We perform comparisons against enums using the underlying type
  520. /// because a more complete set of comparisons can be performed.
  521. /// </summary>
  522. static Expression ConvertEnumExpression(Expression expr, Expression otherExpr)
  523. {
  524. if (!IsEnumType(expr.Type))
  525. {
  526. return expr;
  527. }
  528. Type underlyingType;
  529. if (IsNullableType(expr.Type) ||
  530. (otherExpr.NodeType == ExpressionType.Constant && ((ConstantExpression)otherExpr).Value == null))
  531. {
  532. // if the enum expression itself is nullable or is being compared against null
  533. // we use a nullable type
  534. underlyingType = typeof(Nullable<>).MakeGenericType(Enum.GetUnderlyingType(GetNonNullableType(expr.Type)));
  535. }
  536. else
  537. {
  538. underlyingType = Enum.GetUnderlyingType(expr.Type);
  539. }
  540. return Expression.Convert(expr, underlyingType);
  541. }
  542. // +, -, & operators
  543. Expression ParseAdditive()
  544. {
  545. Expression left = ParseMultiplicative();
  546. while (token.id == TokenId.Plus || token.id == TokenId.Minus ||
  547. token.id == TokenId.Amphersand)
  548. {
  549. Token op = token;
  550. NextToken();
  551. Expression right = ParseMultiplicative();
  552. switch (op.id)
  553. {
  554. case TokenId.Plus:
  555. if (left.Type == typeof(string) || right.Type == typeof(string))
  556. goto case TokenId.Amphersand;
  557. CheckAndPromoteOperands(typeof(IAddSignatures), op.text, ref left, ref right, op.pos);
  558. left = GenerateAdd(left, right);
  559. break;
  560. case TokenId.Minus:
  561. CheckAndPromoteOperands(typeof(ISubtractSignatures), op.text, ref left, ref right, op.pos);
  562. left = GenerateSubtract(left, right);
  563. break;
  564. case TokenId.Amphersand:
  565. left = GenerateStringConcat(left, right);
  566. break;
  567. }
  568. }
  569. return left;
  570. }
  571. // *, /, %, mod operators
  572. Expression ParseMultiplicative()
  573. {
  574. Expression left = ParseUnary();
  575. while (token.id == TokenId.Asterisk || token.id == TokenId.Slash ||
  576. token.id == TokenId.Percent || TokenIdentifierIs("mod"))
  577. {
  578. Token op = token;
  579. NextToken();
  580. Expression right = ParseUnary();
  581. CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.text, ref left, ref right, op.pos);
  582. switch (op.id)
  583. {
  584. case TokenId.Asterisk:
  585. left = Expression.Multiply(left, right);
  586. break;
  587. case TokenId.Slash:
  588. left = Expression.Divide(left, right);
  589. break;
  590. case TokenId.Percent:
  591. case TokenId.Identifier:
  592. left = Expression.Modulo(left, right);
  593. break;
  594. }
  595. }
  596. return left;
  597. }
  598. // -, !, not unary operators
  599. Expression ParseUnary()
  600. {
  601. if (token.id == TokenId.Minus || token.id == TokenId.Exclamation ||
  602. TokenIdentifierIs("not"))
  603. {
  604. Token op = token;
  605. NextToken();
  606. if (op.id == TokenId.Minus && (token.id == TokenId.IntegerLiteral ||
  607. token.id == TokenId.RealLiteral))
  608. {
  609. token.text = "-" + token.text;
  610. token.pos = op.pos;
  611. return ParsePrimary();
  612. }
  613. Expression expr = ParseUnary();
  614. if (op.id == TokenId.Minus)
  615. {
  616. CheckAndPromoteOperand(typeof(INegationSignatures), op.text, ref expr, op.pos);
  617. expr = Expression.Negate(expr);
  618. }
  619. else
  620. {
  621. CheckAndPromoteOperand(typeof(INotSignatures), op.text, ref expr, op.pos);
  622. expr = Expression.Not(expr);
  623. }
  624. return expr;
  625. }
  626. return ParsePrimary();
  627. }
  628. Expression ParsePrimary()
  629. {
  630. Expression expr = ParsePrimaryStart();
  631. while (true)
  632. {
  633. if (token.id == TokenId.Dot)
  634. {
  635. NextToken();
  636. expr = ParseMemberAccess(null, expr);
  637. }
  638. else if (token.id == TokenId.OpenBracket)
  639. {
  640. expr = ParseElementAccess(expr);
  641. }
  642. else
  643. {
  644. break;
  645. }
  646. }
  647. return expr;
  648. }
  649. Expression ParsePrimaryStart()
  650. {
  651. switch (token.id)
  652. {
  653. case TokenId.Identifier:
  654. return ParseIdentifier();
  655. case TokenId.StringLiteral:
  656. return ParseStringLiteral();
  657. case TokenId.IntegerLiteral:
  658. return ParseIntegerLiteral();
  659. case TokenId.RealLiteral:
  660. return ParseRealLiteral();
  661. case TokenId.OpenParen:
  662. return ParseParenExpression();
  663. default:
  664. throw ParseError(SR.ExpressionExpected);
  665. }
  666. }
  667. Expression ParseStringLiteral()
  668. {
  669. ValidateToken(TokenId.StringLiteral);
  670. char quote = token.text[0];
  671. // Unwrap string (remove surrounding quotes) and unwrap backslashes.
  672. string s = token.text.Substring(1, token.text.Length - 2).Replace("\\\\", "\\");
  673. if (quote == '\'')
  674. {
  675. // Unwrap single quotes.
  676. s = s.Replace("\\\'", "\'");
  677. }
  678. else
  679. {
  680. // Unwrap double quotes.
  681. s = s.Replace("\\\"", "\"");
  682. // TODO : do we need this code anymore?
  683. }
  684. NextToken();
  685. return CreateLiteral(s, s);
  686. }
  687. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "Legacy code.")]
  688. Expression ParseIntegerLiteral()
  689. {
  690. ValidateToken(TokenId.IntegerLiteral);
  691. string text = token.text;
  692. if (text[0] != '-')
  693. {
  694. ulong value;
  695. if (!UInt64.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out value))
  696. throw ParseError(SR.InvalidIntegerLiteral(text));
  697. NextToken();
  698. if (value <= (ulong)Int32.MaxValue)
  699. return CreateLiteral((int)value, text);
  700. if (value <= (ulong)UInt32.MaxValue)
  701. return CreateLiteral((uint)value, text);
  702. if (value <= (ulong)Int64.MaxValue)
  703. return CreateLiteral((long)value, text);
  704. return CreateLiteral(value, text);
  705. }
  706. else
  707. {
  708. long value;
  709. if (!Int64.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out value))
  710. throw ParseError(SR.InvalidIntegerLiteral(text));
  711. NextToken();
  712. if (value >= Int32.MinValue && value <= Int32.MaxValue)
  713. return CreateLiteral((int)value, text);
  714. return CreateLiteral(value, text);
  715. }
  716. }
  717. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "Legacy code.")]
  718. Expression ParseRealLiteral()
  719. {
  720. ValidateToken(TokenId.RealLiteral);
  721. string text = token.text;
  722. object value = null;
  723. char last = text[text.Length - 1];
  724. if (last == 'F' || last == 'f')
  725. {
  726. float f;
  727. if (Single.TryParse(text.Substring(0, text.Length - 1), NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out f))
  728. value = f;
  729. }
  730. else if (last == 'M' || last == 'm')
  731. {
  732. decimal m;
  733. if (Decimal.TryParse(text.Substring(0, text.Length - 1), NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out m))
  734. value = m;
  735. }
  736. else if (last == 'D' || last == 'd')
  737. {
  738. double d;
  739. if (Double.TryParse(text.Substring(0, text.Length - 1), NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d))
  740. value = d;
  741. }
  742. else
  743. {
  744. double d;
  745. if (Double.TryParse(text, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out d))
  746. value = d;
  747. }
  748. if (value == null)
  749. throw ParseError(SR.InvalidRealLiteral(text));
  750. NextToken();
  751. return CreateLiteral(value, text);
  752. }
  753. Expression CreateLiteral(object value, string valueAsString)
  754. {
  755. ConstantExpression expr = Expression.Constant(value);
  756. literals.Add(expr, valueAsString);
  757. return expr;
  758. }
  759. Expression ParseParenExpression()
  760. {
  761. ValidateToken(TokenId.OpenParen, SR.OpenParenExpected);
  762. NextToken();
  763. Expression e = ParseExpression();
  764. ValidateToken(TokenId.CloseParen, SR.CloseParenOrOperatorExpected);
  765. NextToken();
  766. return e;
  767. }
  768. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Legacy code.")]
  769. Expression ParseIdentifier()
  770. {
  771. ValidateToken(TokenId.Identifier);
  772. object value;
  773. if (keywords.TryGetValue(token.text, out value))
  774. {
  775. if (value is Type)
  776. return ParseTypeAccess((Type)value);
  777. if (value == (object)keywordIt)
  778. return ParseIt();
  779. if (value == (object)keywordIif)
  780. return ParseIif();
  781. NextToken();
  782. return (Expression)value;
  783. }
  784. if (symbols.TryGetValue(token.text, out value))
  785. {
  786. Expression expr = value as Expression;
  787. if (expr == null)
  788. {
  789. expr = Expression.Constant(value);
  790. }
  791. NextToken();
  792. return expr;
  793. }
  794. // See if the token is a mapped function call
  795. MappedMemberInfo mappedFunction = MapFunction(token.text);
  796. if (mappedFunction != null)
  797. {
  798. return ParseMappedFunction(mappedFunction);
  799. }
  800. if (it != null)
  801. return ParseMemberAccess(null, it);
  802. throw ParseError(SR.UnknownIdentifier(token.text));
  803. }
  804. MappedMemberInfo MapFunction(string functionName)
  805. {
  806. MappedMemberInfo mappedMember = MapStringFunction(functionName);
  807. if (mappedMember != null)
  808. {
  809. return mappedMember;
  810. }
  811. mappedMember = MapDateFunction(functionName);
  812. if (mappedMember != null)
  813. {
  814. return mappedMember;
  815. }
  816. mappedMember = MapMathFunction(functionName);
  817. if (mappedMember != null)
  818. {
  819. return mappedMember;
  820. }
  821. return null;
  822. }
  823. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Legacy code.")]
  824. MappedMemberInfo MapStringFunction(string functionName)
  825. {
  826. if (functionName == "startswith")
  827. {
  828. return new MappedMemberInfo(typeof(string), "StartsWith", false, true);
  829. }
  830. else if (functionName == "endswith")
  831. {
  832. return new MappedMemberInfo(typeof(string), "EndsWith", false, true);
  833. }
  834. else if (functionName == "length")
  835. {
  836. return new MappedMemberInfo(typeof(string), "Length", false, false);
  837. }
  838. else if (functionName == "toupper")
  839. {
  840. return new MappedMemberInfo(typeof(string), "ToUpper", false, true);
  841. }
  842. else if (functionName == "tolower")
  843. {
  844. return new MappedMemberInfo(typeof(string), "ToLower", false, true);
  845. }
  846. else if (functionName == "substringof")
  847. {
  848. return new MappedMemberInfo(typeof(string), "Contains", false, true);
  849. }
  850. else if (functionName == "indexof")
  851. {
  852. return new MappedMemberInfo(typeof(string), "IndexOf", false, true);
  853. }
  854. else if (functionName == "replace")
  855. {
  856. return new MappedMemberInfo(typeof(string), "Replace", false, true);
  857. }
  858. else if (functionName == "substring")
  859. {
  860. return new MappedMemberInfo(typeof(string), "Substring", false, true);
  861. }
  862. else if (functionName == "trim")
  863. {
  864. return new MappedMemberInfo(typeof(string), "Trim", false, true);
  865. }
  866. else if (functionName == "concat")
  867. {
  868. return new MappedMemberInfo(typeof(string), "Concat", true, true);
  869. }
  870. return null;
  871. }
  872. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Legacy code.")]
  873. MappedMemberInfo MapDateFunction(string functionName)
  874. {
  875. // date functions
  876. if (functionName == "day")
  877. {
  878. return new MappedMemberInfo(typeof(DateTime), "Day", false, false);
  879. }
  880. else if (functionName == "month")
  881. {
  882. return new MappedMemberInfo(typeof(DateTime), "Month", false, false);
  883. }
  884. else if (functionName == "year")
  885. {
  886. return new MappedMemberInfo(typeof(DateTime), "Year", false, false);
  887. }
  888. else if (functionName == "hour")
  889. {
  890. return new MappedMemberInfo(typeof(DateTime), "Hour", false, false);
  891. }
  892. else if (functionName == "minute")
  893. {
  894. return new MappedMemberInfo(typeof(DateTime), "Minute", false, false);
  895. }
  896. else if (functionName == "second")
  897. {
  898. return new MappedMemberInfo(typeof(DateTime), "Second", false, false);
  899. }
  900. return null;
  901. }
  902. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Legacy code.")]
  903. MappedMemberInfo MapMathFunction(string functionName)
  904. {
  905. if (functionName == "round")
  906. {
  907. return new MappedMemberInfo(typeof(Math), "Round", true, true);
  908. }
  909. if (functionName == "floor")
  910. {
  911. return new MappedMemberInfo(typeof(Math), "Floor", true, true);
  912. }
  913. if (functionName == "ceiling")
  914. {
  915. return new MappedMemberInfo(typeof(Math), "Ceiling", true, true);
  916. }
  917. return null;
  918. }
  919. Expression ParseIt()
  920. {
  921. if (it == null)
  922. throw ParseError(SR.NoItInScope);
  923. NextToken();
  924. return it;
  925. }
  926. Expression ParseIif()
  927. {
  928. int errorPos = token.pos;
  929. NextToken();
  930. Expression[] args = ParseArgumentList();
  931. if (args.Length != 3)
  932. throw ParseError(errorPos, SR.IifRequiresThreeArgs);
  933. return GenerateConditional(args[0], args[1], args[2], errorPos);
  934. }
  935. Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
  936. {
  937. if (test.Type != typeof(bool))
  938. throw ParseError(errorPos, SR.FirstExprMustBeBool);
  939. if (expr1.Type != expr2.Type)
  940. {
  941. Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
  942. Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
  943. if (expr1as2 != null && expr2as1 == null)
  944. {
  945. expr1 = expr1as2;
  946. }
  947. else if (expr2as1 != null && expr1as2 == null)
  948. {
  949. expr2 = expr2as1;
  950. }
  951. else
  952. {
  953. string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";
  954. string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";
  955. if (expr1as2 != null && expr2as1 != null)
  956. throw ParseError(errorPos, SR.BothTypesConvertToOther(type1, type2));
  957. throw ParseError(errorPos, SR.NeitherTypeConvertsToOther(type1, type2));
  958. }
  959. }
  960. return Expression.Condition(test, expr1, expr2);
  961. }
  962. Expression ParseTypeAccess(Type type)
  963. {
  964. int errorPos = token.pos;
  965. NextToken();
  966. if (token.id == TokenId.Question)
  967. {
  968. if (!type.IsValueType || IsNullableType(type))
  969. throw ParseError(errorPos, SR.TypeHasNoNullableForm(GetTypeName(type)));
  970. type = typeof(Nullable<>).MakeGenericType(type);
  971. NextToken();
  972. }
  973. if (token.id == TokenId.OpenParen)
  974. {
  975. Expression[] args = ParseArgumentList();
  976. MethodBase method;
  977. switch (FindBestMethod(type.GetConstructors(), args, out method))
  978. {
  979. case 0:
  980. if (args.Length == 1)
  981. return GenerateConversion(args[0], type, errorPos);
  982. throw ParseError(errorPos, SR.NoMatchingConstructor(GetTypeName(type)));
  983. case 1:
  984. return Expression.New((ConstructorInfo)method, args);
  985. default:
  986. throw ParseError(errorPos, SR.AmbiguousConstructorInvocation(GetTypeName(type)));
  987. }
  988. }
  989. ValidateToken(TokenId.Dot, SR.DotOrOpenParenExpected);
  990. NextToken();
  991. return ParseMemberAccess(type, null);
  992. }
  993. static Expression GenerateConversion(Expression expr, Type type, int errorPos)
  994. {
  995. Type exprType = expr.Type;
  996. if (exprType == type)
  997. return expr;
  998. if (exprType.IsValueType && type.IsValueType)
  999. {
  1000. if ((IsNullableType(exprType) || IsNullableType(type)) &&
  1001. GetNonNullableType(exprType) == GetNonNullableType(type))
  1002. return Expression.Convert(expr, type);
  1003. if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
  1004. (IsNumericType(type) || IsEnumType(type)))
  1005. return Expression.ConvertChecked(expr, type);
  1006. }
  1007. if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
  1008. exprType.IsInterface || type.IsInterface)
  1009. return Expression.Convert(expr, type);
  1010. throw ParseError(errorPos, SR.CannotConvertValue(
  1011. GetTypeName(exprType), GetTypeName(type)));
  1012. }
  1013. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Legacy code.")]
  1014. Expression ParseMappedFunction(MappedMemberInfo mappedMember)
  1015. {
  1016. Type type = mappedMember.MappedType;
  1017. string mappedMemberName = mappedMember.MemberName;
  1018. int errorPos = token.pos;
  1019. Expression[] args = null;
  1020. Expression paramArg = null;
  1021. Expression instance = null;
  1022. NextToken();
  1023. if (token.id == TokenId.OpenParen)
  1024. {
  1025. args = ParseArgumentList();
  1026. // TODO : verify the first argument is the param
  1027. // Really what we'll want to do here is allow either to be the param
  1028. paramArg = args[0];
  1029. instance = paramArg;
  1030. // static methods need to include the target
  1031. if (!mappedMember.IsStatic)
  1032. {
  1033. args = args.Skip(1).ToArray();
  1034. }
  1035. else
  1036. {
  1037. instance = null;
  1038. }
  1039. }
  1040. if (mappedMember.IsMethod)
  1041. {
  1042. // a mapped function
  1043. MethodBase mb;
  1044. switch (FindMethod(type, mappedMemberName, mappedMember.IsStatic, args, out mb))
  1045. {
  1046. case 0:
  1047. throw ParseError(errorPos, SR.NoApplicableMethod(
  1048. mappedMemberName, GetTypeName(type)));
  1049. case 1:
  1050. MethodInfo method = (MethodInfo)mb;
  1051. if (!IsPredefinedType(method.DeclaringType))
  1052. throw ParseError(errorPos, SR.MethodsAreInaccessible(GetTypeName(method.DeclaringType)));
  1053. if (method.ReturnType == typeof(void))
  1054. throw ParseError(errorPos, SR.MethodIsVoid(
  1055. mappedMemberName, GetTypeName(method.DeclaringType)));
  1056. return Expression.Call(instance, (MethodInfo)method, args);
  1057. default:
  1058. throw ParseError(errorPos, SR.AmbiguousMethodInvocation(
  1059. mappedMemberName, GetTypeName(type)));
  1060. }
  1061. }
  1062. else
  1063. {
  1064. // a mapped Property/Field
  1065. MemberInfo member = FindPropertyOrField(type, mappedMemberName, mappedMember.IsStatic);
  1066. if (member == null)
  1067. {
  1068. if (this.queryResolver != null)
  1069. {
  1070. MemberExpression mex = queryResolver.ResolveMember(type, mappedMemberName, instance);
  1071. if (mex != null)
  1072. {
  1073. return mex;
  1074. }
  1075. }
  1076. throw ParseError(errorPos, SR.UnknownPropertyOrField(
  1077. mappedMemberName, GetTypeName(type)));
  1078. }
  1079. return member is PropertyInfo ?
  1080. Expression.Property(instance, (PropertyInfo)member) :
  1081. Expression.Field(instance, (FieldInfo)member);
  1082. }
  1083. }
  1084. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Legacy code.")]
  1085. Expression ParseMemberAccess(Type type, Expression instance)
  1086. {
  1087. if (instance != null)
  1088. type = instance.Type;
  1089. int errorPos = token.pos;
  1090. string id = GetIdentifier();
  1091. NextToken();
  1092. if (token.id == TokenId.OpenParen)
  1093. {
  1094. if (instance != null && type != typeof(string))
  1095. {
  1096. Type enumerableType = FindGenericType(typeof(IEnumerable<>), type);
  1097. if (enumerableType != null)
  1098. {
  1099. Type elementType = enumerableType.GetGenericArguments()[0];
  1100. return ParseAggregate(instance, elementType, id, errorPos);
  1101. }
  1102. }
  1103. Expression[] args = ParseArgumentList();
  1104. MethodBase mb;
  1105. switch (FindMethod(type, id, instance == null, args, out mb))
  1106. {
  1107. case 0:
  1108. throw ParseError(errorPos, SR.NoApplicableMethod(
  1109. id, GetTypeName(type)));
  1110. case 1:
  1111. MethodInfo method = (MethodInfo)mb;
  1112. if (!IsPredefinedType(method.DeclaringType))
  1113. throw ParseError(errorPos, SR.MethodsAreInaccessible(GetTypeName(method.DeclaringType)));
  1114. if (method.ReturnType == typeof(void))
  1115. throw ParseError(errorPos, SR.MethodIsVoid(
  1116. id, GetTypeName(method.DeclaringType)));
  1117. return Expression.Call(instance, (MethodInfo)method, args);
  1118. default:
  1119. throw ParseError(errorPos, SR.AmbiguousMethodInvocation(
  1120. id, GetTypeName(type)));
  1121. }
  1122. }
  1123. else
  1124. {
  1125. MemberInfo member = FindPropertyOrField(type, id, instance == null);
  1126. if (member == null)
  1127. {
  1128. if (this.queryResolver != null)
  1129. {
  1130. MemberExpression mex = queryResolver.ResolveMember(type, id, instance);
  1131. if (mex != null)
  1132. {
  1133. return mex;
  1134. }
  1135. }
  1136. throw ParseError(errorPos, SR.UnknownPropertyOrField(
  1137. id, GetTypeName(type)));
  1138. }
  1139. return member is PropertyInfo ?
  1140. Expression.Property(instance, (PropertyInfo)member) :
  1141. Expression.Field(instance, (FieldInfo)member);
  1142. }
  1143. }
  1144. static Type FindGenericType(Type generic, Type type)
  1145. {
  1146. while (type != null && type != typeof(object))
  1147. {
  1148. if (type.IsGenericType && type.GetGenericTypeDefinition() == generic)
  1149. return typ

Large files files are truncated, but you can click here to view the full file