PageRenderTime 60ms CodeModel.GetById 19ms 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
  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 type;
  1150. if (generic.IsInterface)
  1151. {
  1152. foreach (Type intfType in type.GetInterfaces())
  1153. {
  1154. Type found = FindGenericType(generic, intfType);
  1155. if (found != null)
  1156. return found;
  1157. }
  1158. }
  1159. type = type.BaseType;
  1160. }
  1161. return null;
  1162. }
  1163. Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
  1164. {
  1165. ParameterExpression outerIt = it;
  1166. ParameterExpression innerIt = Expression.Parameter(elementType, "");
  1167. it = innerIt;
  1168. Expression[] args = ParseArgumentList();
  1169. it = outerIt;
  1170. MethodBase signature;
  1171. if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
  1172. throw ParseError(errorPos, SR.NoApplicableAggregate(methodName));
  1173. Type[] typeArgs;
  1174. if (signature.Name == "Min" || signature.Name == "Max")
  1175. {
  1176. typeArgs = new Type[] { elementType, args[0].Type };
  1177. }
  1178. else
  1179. {
  1180. typeArgs = new Type[] { elementType };
  1181. }
  1182. if (args.Length == 0)
  1183. {
  1184. args = new Expression[] { instance };
  1185. }
  1186. else
  1187. {
  1188. args = new Expression[] { instance, DynamicExpression.Lambda(args[0], innerIt) };
  1189. }
  1190. return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
  1191. }
  1192. Expression[] ParseArgumentList()
  1193. {
  1194. ValidateToken(TokenId.OpenParen, SR.OpenParenExpected);
  1195. NextToken();
  1196. Expression[] args = token.id != TokenId.CloseParen ? ParseArguments() : new Expression[0];
  1197. ValidateToken(TokenId.CloseParen, SR.CloseParenOrCommaExpected);
  1198. NextToken();
  1199. return args;
  1200. }
  1201. Expression[] ParseArguments()
  1202. {
  1203. List<Expression> argList = new List<Expression>();
  1204. while (true)
  1205. {
  1206. argList.Add(ParseExpression());
  1207. if (token.id != TokenId.Comma)
  1208. break;
  1209. NextToken();
  1210. }
  1211. return argList.ToArray();
  1212. }
  1213. Expression ParseElementAccess(Expression expr)
  1214. {
  1215. int errorPos = token.pos;
  1216. ValidateToken(TokenId.OpenBracket, SR.OpenParenExpected);
  1217. NextToken();
  1218. Expression[] args = ParseArguments();
  1219. ValidateToken(TokenId.CloseBracket, SR.CloseBracketOrCommaExpected);
  1220. NextToken();
  1221. if (expr.Type.IsArray)
  1222. {
  1223. if (expr.Type.GetArrayRank() != 1 || args.Length != 1)
  1224. throw ParseError(errorPos, SR.CannotIndexMultiDimArray);
  1225. Expression index = PromoteExpression(args[0], typeof(int), true);
  1226. if (index == null)
  1227. throw ParseError(errorPos, SR.InvalidIndex);
  1228. return Expression.ArrayIndex(expr, index);
  1229. }
  1230. else
  1231. {
  1232. MethodBase mb;
  1233. switch (FindIndexer(expr.Type, args, out mb))
  1234. {
  1235. case 0:
  1236. throw ParseError(errorPos, SR.NoApplicableIndexer(
  1237. GetTypeName(expr.Type)));
  1238. case 1:
  1239. return Expression.Call(expr, (MethodInfo)mb, args);
  1240. default:
  1241. throw ParseError(errorPos, SR.AmbiguousIndexerInvocation(
  1242. GetTypeName(expr.Type)));
  1243. }
  1244. }
  1245. }
  1246. static bool IsPredefinedType(Type type)
  1247. {
  1248. type = GetNonNullableType(type);
  1249. foreach (Type t in predefinedTypes)
  1250. if (t == type)
  1251. return true;
  1252. return false;
  1253. }
  1254. static bool IsNullableType(Type type)
  1255. {
  1256. return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
  1257. }
  1258. static Type GetNonNullableType(Type type)
  1259. {
  1260. return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
  1261. }
  1262. internal static string GetTypeName(Type type)
  1263. {
  1264. Type baseType = GetNonNullableType(type);
  1265. string s = baseType.Name;
  1266. if (type != baseType)
  1267. s += '?';
  1268. return s;
  1269. }
  1270. static bool IsNumericType(Type type)
  1271. {
  1272. return GetNumericTypeKind(type) != 0;
  1273. }
  1274. static bool IsSignedIntegralType(Type type)
  1275. {
  1276. return GetNumericTypeKind(type) == 2;
  1277. }
  1278. static bool IsUnsignedIntegralType(Type type)
  1279. {
  1280. return GetNumericTypeKind(type) == 3;
  1281. }
  1282. static int GetNumericTypeKind(Type type)
  1283. {
  1284. type = GetNonNullableType(type);
  1285. if (type.IsEnum)
  1286. return 0;
  1287. switch (Type.GetTypeCode(type))
  1288. {
  1289. case TypeCode.Char:
  1290. case TypeCode.Single:
  1291. case TypeCode.Double:
  1292. case TypeCode.Decimal:
  1293. return 1;
  1294. case TypeCode.SByte:
  1295. case TypeCode.Int16:
  1296. case TypeCode.Int32:
  1297. case TypeCode.Int64:
  1298. return 2;
  1299. case TypeCode.Byte:
  1300. case TypeCode.UInt16:
  1301. case TypeCode.UInt32:
  1302. case TypeCode.UInt64:
  1303. return 3;
  1304. default:
  1305. return 0;
  1306. }
  1307. }
  1308. static bool IsEnumType(Type type)
  1309. {
  1310. return GetNonNullableType(type).IsEnum;
  1311. }
  1312. void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
  1313. {
  1314. Expression[] args = new Expression[] { expr };
  1315. MethodBase method;
  1316. if (FindMethod(signatures, "F", false, args, out method) != 1)
  1317. throw ParseError(errorPos, SR.IncompatibleOperand(
  1318. opName, GetTypeName(args[0].Type)));
  1319. expr = args[0];
  1320. }
  1321. void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
  1322. {
  1323. Expression[] args = new Expression[] { left, right };
  1324. MethodBase method;
  1325. if (FindMethod(signatures, "F", false, args, out method) != 1)
  1326. throw IncompatibleOperandsError(opName, left, right, errorPos);
  1327. left = args[0];
  1328. right = args[1];
  1329. }
  1330. static Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
  1331. {
  1332. return ParseError(pos, SR.IncompatibleOperands(
  1333. opName, GetTypeName(left.Type), GetTypeName(right.Type)));
  1334. }
  1335. static MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
  1336. {
  1337. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1338. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1339. foreach (Type t in SelfAndBaseTypes(type))
  1340. {
  1341. MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
  1342. flags, Type.FilterNameIgnoreCase, memberName);
  1343. if (members.Length != 0)
  1344. return members[0];
  1345. }
  1346. return null;
  1347. }
  1348. int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
  1349. {
  1350. BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
  1351. (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
  1352. foreach (Type t in SelfAndBaseTypes(type))
  1353. {
  1354. MemberInfo[] members = t.FindMembers(MemberTypes.Method,
  1355. flags, Type.FilterNameIgnoreCase, methodName);
  1356. int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);
  1357. if (count != 0)
  1358. return count;
  1359. }
  1360. method = null;
  1361. return 0;
  1362. }
  1363. int FindIndexer(Type type, Expression[] args, out MethodBase method)
  1364. {
  1365. foreach (Type t in SelfAndBaseTypes(type))
  1366. {
  1367. MemberInfo[] members = t.GetDefaultMembers();
  1368. if (members.Length != 0)
  1369. {
  1370. IEnumerable<MethodBase> methods = members.
  1371. OfType<PropertyInfo>().
  1372. Select(p => (MethodBase)p.GetGetMethod()).
  1373. Where(m => m != null);
  1374. int count = FindBestMethod(methods, args, out method);
  1375. if (count != 0)
  1376. return count;
  1377. }
  1378. }
  1379. method = null;
  1380. return 0;
  1381. }
  1382. static IEnumerable<Type> SelfAndBaseTypes(Type type)
  1383. {
  1384. if (type.IsInterface)
  1385. {
  1386. List<Type> types = new List<Type>();
  1387. AddInterface(types, type);
  1388. return types;
  1389. }
  1390. return SelfAndBaseClasses(type);
  1391. }
  1392. static IEnumerable<Type> SelfAndBaseClasses(Type type)
  1393. {
  1394. while (type != null)
  1395. {
  1396. yield return type;
  1397. type = type.BaseType;
  1398. }
  1399. }
  1400. static void AddInterface(List<Type> types, Type type)
  1401. {
  1402. if (!types.Contains(type))
  1403. {
  1404. types.Add(type);
  1405. foreach (Type t in type.GetInterfaces())
  1406. AddInterface(types, t);
  1407. }
  1408. }
  1409. class MethodData
  1410. {
  1411. public MethodBase MethodBase;
  1412. public ParameterInfo[] Parameters;
  1413. public Expression[] Args;
  1414. }
  1415. int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
  1416. {
  1417. MethodData[] applicable = methods.
  1418. Select(m => new MethodData
  1419. {
  1420. MethodBase = m,
  1421. Parameters = m.GetParameters()
  1422. }).
  1423. Where(m => IsApplicable(m, args)).
  1424. ToArray();
  1425. if (applicable.Length > 1)
  1426. {
  1427. applicable = applicable.
  1428. Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
  1429. ToArray();
  1430. }
  1431. if (applicable.Length == 1)
  1432. {
  1433. MethodData md = applicable[0];
  1434. for (int i = 0; i < args.Length; i++)
  1435. args[i] = md.Args[i];
  1436. method = md.MethodBase;
  1437. }
  1438. else
  1439. {
  1440. method = null;
  1441. }
  1442. return applicable.Length;
  1443. }
  1444. bool IsApplicable(MethodData method, Expression[] args)
  1445. {
  1446. if (method.Parameters.Length != args.Length)
  1447. return false;
  1448. Expression[] promotedArgs = new Expression[args.Length];
  1449. for (int i = 0; i < args.Length; i++)
  1450. {
  1451. ParameterInfo pi = method.Parameters[i];
  1452. if (pi.IsOut)
  1453. return false;
  1454. Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
  1455. if (promoted == null)
  1456. return false;
  1457. promotedArgs[i] = promoted;
  1458. }
  1459. method.Args = promotedArgs;
  1460. return true;
  1461. }
  1462. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "Legacy code.")]
  1463. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Legacy code.")]
  1464. Expression PromoteExpression(Expression expr, Type type, bool exact)
  1465. {
  1466. if (expr.Type == type)
  1467. return expr;
  1468. if (expr is ConstantExpression)
  1469. {
  1470. ConstantExpression ce = (ConstantExpression)expr;
  1471. if (ce == nullLiteral)
  1472. {
  1473. if (!type.IsValueType || IsNullableType(type))
  1474. return Expression.Constant(null, type);
  1475. }
  1476. else
  1477. {
  1478. string text;
  1479. if (literals.TryGetValue(ce, out text))
  1480. {
  1481. Type target = GetNonNullableType(type);
  1482. Object value = null;
  1483. switch (Type.GetTypeCode(ce.Type))
  1484. {
  1485. case TypeCode.Int32:
  1486. case TypeCode.UInt32:
  1487. case TypeCode.Int64:
  1488. case TypeCode.UInt64:
  1489. if (target.IsEnum)
  1490. {
  1491. // promoting from a number to an enum
  1492. value = Enum.Parse(target, text);
  1493. }
  1494. else if (target == typeof(char))
  1495. {
  1496. // promote from a number to a char
  1497. value = Convert.ToChar(ce.Value, CultureInfo.InvariantCulture);
  1498. }
  1499. else
  1500. {
  1501. value = ParseNumber(text, target);
  1502. }
  1503. break;
  1504. case TypeCode.Double:
  1505. if (target == typeof(decimal))
  1506. value = ParseNumber(text, target);
  1507. break;
  1508. case TypeCode.String:
  1509. value = ParseEnum(text, target);
  1510. break;
  1511. }
  1512. if (value != null)
  1513. return Expression.Constant(value, type);
  1514. }
  1515. }
  1516. }
  1517. if (IsCompatibleWith(expr.Type, type))
  1518. {
  1519. if (type.IsValueType || exact)
  1520. return Expression.Convert(expr, type);
  1521. return expr;
  1522. }
  1523. return null;
  1524. }
  1525. static object ParseNumber(string text, Type type)
  1526. {
  1527. switch (Type.GetTypeCode(GetNonNullableType(type)))
  1528. {
  1529. case TypeCode.SByte:
  1530. sbyte sb;
  1531. if (sbyte.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out sb))
  1532. return sb;
  1533. break;
  1534. case TypeCode.Byte:
  1535. byte b;
  1536. if (byte.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out b))
  1537. return b;
  1538. break;
  1539. case TypeCode.Int16:
  1540. short s;
  1541. if (short.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out s))
  1542. return s;
  1543. break;
  1544. case TypeCode.UInt16:
  1545. ushort us;
  1546. if (ushort.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out us))
  1547. return us;
  1548. break;
  1549. case TypeCode.Int32:
  1550. int i;
  1551. if (int.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out i))
  1552. return i;
  1553. break;
  1554. case TypeCode.UInt32:
  1555. uint ui;
  1556. if (uint.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out ui))
  1557. return ui;
  1558. break;
  1559. case TypeCode.Int64:
  1560. long l;
  1561. if (long.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out l))
  1562. return l;
  1563. break;
  1564. case TypeCode.UInt64:
  1565. ulong ul;
  1566. if (ulong.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out ul))
  1567. return ul;
  1568. break;
  1569. case TypeCode.Single:
  1570. float f;
  1571. if (float.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out f))
  1572. return f;
  1573. break;
  1574. case TypeCode.Double:
  1575. double d;
  1576. if (double.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out d))
  1577. return d;
  1578. break;
  1579. case TypeCode.Decimal:
  1580. decimal e;
  1581. if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out e))
  1582. return e;
  1583. break;
  1584. }
  1585. return null;
  1586. }
  1587. static object ParseEnum(string name, Type type)
  1588. {
  1589. if (type.IsEnum)
  1590. {
  1591. MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
  1592. BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
  1593. Type.FilterNameIgnoreCase, name);
  1594. if (memberInfos.Length != 0)
  1595. return ((FieldInfo)memberInfos[0]).GetValue(null);
  1596. }
  1597. return null;
  1598. }
  1599. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Legacy code.")]
  1600. static bool IsCompatibleWith(Type source, Type target)
  1601. {
  1602. if (source == target)
  1603. return true;
  1604. if (!target.IsValueType)
  1605. return target.IsAssignableFrom(source);
  1606. Type st = GetNonNullableType(source);
  1607. Type tt = GetNonNullableType(target);
  1608. if (st != source && tt == target)
  1609. return false;
  1610. TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);
  1611. TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);
  1612. switch (sc)
  1613. {
  1614. case TypeCode.SByte:
  1615. switch (tc)
  1616. {
  1617. case TypeCode.SByte:
  1618. case TypeCode.Int16:
  1619. case TypeCode.Int32:
  1620. case TypeCode.Int64:
  1621. case TypeCode.Single:
  1622. case TypeCode.Double:
  1623. case TypeCode.Decimal:
  1624. return true;
  1625. }
  1626. break;
  1627. case TypeCode.Byte:
  1628. switch (tc)
  1629. {
  1630. case TypeCode.Byte:
  1631. case TypeCode.Int16:
  1632. case TypeCode.UInt16:
  1633. case TypeCode.Int32:
  1634. case TypeCode.UInt32:
  1635. case TypeCode.Int64:
  1636. case TypeCode.UInt64:
  1637. case TypeCode.Single:
  1638. case TypeCode.Double:
  1639. case TypeCode.Decimal:
  1640. return true;
  1641. }
  1642. break;
  1643. case TypeCode.Int16:
  1644. switch (tc)
  1645. {
  1646. case TypeCode.Int16:
  1647. case TypeCode.Int32:
  1648. case TypeCode.Int64:
  1649. case TypeCode.Single:
  1650. case TypeCode.Double:
  1651. case TypeCode.Decimal:
  1652. return true;
  1653. }
  1654. break;
  1655. case TypeCode.UInt16:
  1656. switch (tc)
  1657. {
  1658. case TypeCode.UInt16:
  1659. case TypeCode.Int32:
  1660. case TypeCode.UInt32:
  1661. case TypeCode.Int64:
  1662. case TypeCode.UInt64:
  1663. case TypeCode.Single:
  1664. case TypeCode.Double:
  1665. case TypeCode.Decimal:
  1666. return true;
  1667. }
  1668. break;
  1669. case TypeCode.Int32:
  1670. switch (tc)
  1671. {
  1672. case TypeCode.Int32:
  1673. case TypeCode.Int64:
  1674. case TypeCode.Single:
  1675. case TypeCode.Double:
  1676. case TypeCode.Decimal:
  1677. return true;
  1678. }
  1679. break;
  1680. case TypeCode.UInt32:
  1681. switch (tc)
  1682. {
  1683. case TypeCode.UInt32:
  1684. case TypeCode.Int64:
  1685. case TypeCode.UInt64:
  1686. case TypeCode.Single:
  1687. case TypeCode.Double:
  1688. case TypeCode.Decimal:
  1689. return true;
  1690. }
  1691. break;
  1692. case TypeCode.Int64:
  1693. switch (tc)
  1694. {
  1695. case TypeCode.Int64:
  1696. case TypeCode.Single:
  1697. case TypeCode.Double:
  1698. case TypeCode.Decimal:
  1699. return true;
  1700. }
  1701. break;
  1702. case TypeCode.UInt64:
  1703. switch (tc)
  1704. {
  1705. case TypeCode.UInt64:
  1706. case TypeCode.Single:
  1707. case TypeCode.Double:
  1708. case TypeCode.Decimal:
  1709. return true;
  1710. }
  1711. break;
  1712. case TypeCode.Single:
  1713. switch (tc)
  1714. {
  1715. case TypeCode.Single:
  1716. case TypeCode.Double:
  1717. return true;
  1718. }
  1719. break;
  1720. default:
  1721. if (st == tt)
  1722. return true;
  1723. break;
  1724. }
  1725. return false;
  1726. }
  1727. static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
  1728. {
  1729. bool better = false;
  1730. for (int i = 0; i < args.Length; i++)
  1731. {
  1732. int c = CompareConversions(args[i].Type,
  1733. m1.Parameters[i].ParameterType,
  1734. m2.Parameters[i].ParameterType);
  1735. if (c < 0)
  1736. return false;
  1737. if (c > 0)
  1738. better = true;
  1739. }
  1740. return better;
  1741. }
  1742. // Return 1 if s -> t1 is a better conversion than s -> t2
  1743. // Return -1 if s -> t2 is a better conversion than s -> t1
  1744. // Return 0 if neither conversion is better
  1745. static int CompareConversions(Type s, Type t1, Type t2)
  1746. {
  1747. if (t1 == t2)
  1748. return 0;
  1749. if (s == t1)
  1750. return 1;
  1751. if (s == t2)
  1752. return -1;
  1753. bool t1t2 = IsCompatibleWith(t1, t2);
  1754. bool t2t1 = IsCompatibleWith(t2, t1);
  1755. if (t1t2 && !t2t1)
  1756. return 1;
  1757. if (t2t1 && !t1t2)
  1758. return -1;
  1759. if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2))
  1760. return 1;
  1761. if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1))
  1762. return -1;
  1763. return 0;
  1764. }
  1765. static Expression GenerateEqual(Expression left, Expression right)
  1766. {
  1767. return Expression.Equal(left, right);
  1768. }
  1769. static Expression GenerateNotEqual(Expression left, Expression right)
  1770. {
  1771. return Expression.NotEqual(left, right);
  1772. }
  1773. static Expression GenerateGreaterThan(Expression left, Expression right)
  1774. {
  1775. if (left.Type == typeof(string))
  1776. {
  1777. return Expression.GreaterThan(
  1778. GenerateStaticMethodCall("Compare", left, right),
  1779. Expression.Constant(0)
  1780. );
  1781. }
  1782. return Expression.GreaterThan(left, right);
  1783. }
  1784. static Expression GenerateGreaterThanEqual(Expression left, Expression right)
  1785. {
  1786. if (left.Type == typeof(string))
  1787. {
  1788. return Expression.GreaterThanOrEqual(
  1789. GenerateStaticMethodCall("Compare", left, right),
  1790. Expression.Constant(0)
  1791. );
  1792. }
  1793. return Expression.GreaterThanOrEqual(left, right);
  1794. }
  1795. static Expression GenerateLessThan(Expression left, Expression right)
  1796. {
  1797. if (left.Type == typeof(string))
  1798. {
  1799. return Expression.LessThan(
  1800. GenerateStaticMethodCall("Compare", left, right),
  1801. Expression.Constant(0)
  1802. );
  1803. }
  1804. return Expression.LessThan(left, right);
  1805. }
  1806. static Expression GenerateLessThanEqual(Expression left, Expression right)
  1807. {
  1808. if (left.Type == typeof(string))
  1809. {
  1810. return Expression.LessThanOrEqual(
  1811. GenerateStaticMethodCall("Compare", left, right),
  1812. Expression.Constant(0)
  1813. );
  1814. }
  1815. return Expression.LessThanOrEqual(left, right);
  1816. }
  1817. static Expression GenerateAdd(Expression left, Expression right)
  1818. {
  1819. if (left.Type == typeof(string) && right.Type == typeof(string))
  1820. {
  1821. return GenerateStaticMethodCall("Concat", left, right);
  1822. }
  1823. return Expression.Add(left, right);
  1824. }
  1825. static Expression GenerateSubtract(Expression left, Expression right)
  1826. {
  1827. return Expression.Subtract(left, right);
  1828. }
  1829. static Expression GenerateStringConcat(Expression left, Expression right)
  1830. {
  1831. if (left.Type.IsValueType)
  1832. left = Expression.Convert(left, typeof(object));
  1833. if (right.Type.IsValueType)
  1834. right = Expression.Convert(right, typeof(object));
  1835. return Expression.Call(
  1836. null,
  1837. typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
  1838. new[] { left, right });
  1839. }
  1840. static MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
  1841. {
  1842. return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
  1843. }
  1844. static Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
  1845. {
  1846. return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
  1847. }
  1848. void SetTextPos(int pos)
  1849. {
  1850. textPos = pos;
  1851. ch = textPos < textLen ? text[textPos] : '\0';
  1852. }
  1853. void NextChar()
  1854. {
  1855. if (textPos < textLen)
  1856. textPos++;
  1857. ch = textPos < textLen ? text[textPos] : '\0';
  1858. }
  1859. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Legacy code.")]
  1860. void NextToken()
  1861. {
  1862. while (Char.IsWhiteSpace(ch))
  1863. NextChar();
  1864. TokenId t;
  1865. int tokenPos = textPos;
  1866. switch (ch)
  1867. {
  1868. case '%':
  1869. NextChar();
  1870. t = TokenId.Percent;
  1871. break;
  1872. case '&':
  1873. NextChar();
  1874. if (ch == '&')
  1875. {
  1876. NextChar();
  1877. t = TokenId.DoubleAmphersand;
  1878. }
  1879. else
  1880. {
  1881. t = TokenId.Amphersand;
  1882. }
  1883. break;
  1884. case '(':
  1885. NextChar();
  1886. t = TokenId.OpenParen;
  1887. break;
  1888. case ')':
  1889. NextChar();
  1890. t = TokenId.CloseParen;
  1891. break;
  1892. case ',':
  1893. NextChar();
  1894. t = TokenId.Comma;
  1895. break;
  1896. case '/':
  1897. NextChar();
  1898. t = TokenId.Dot;
  1899. break;
  1900. case ':':
  1901. NextChar();
  1902. t = TokenId.Colon;
  1903. break;
  1904. case '?':
  1905. NextChar();
  1906. t = TokenId.Question;
  1907. break;
  1908. case '[':
  1909. NextChar();
  1910. t = TokenId.OpenBracket;
  1911. break;
  1912. case ']':
  1913. NextChar();
  1914. t = TokenId.CloseBracket;
  1915. break;
  1916. case '|':
  1917. NextChar();
  1918. if (ch == '|')
  1919. {
  1920. NextChar();
  1921. t = TokenId.DoubleBar;
  1922. }
  1923. else
  1924. {
  1925. t = TokenId.Bar;
  1926. }
  1927. break;
  1928. case '"':
  1929. case '\'':
  1930. char quote = ch;
  1931. do
  1932. {
  1933. NextChar();
  1934. while (textPos < textLen && ch != quote)
  1935. {
  1936. if (ch == '\\')
  1937. {
  1938. NextChar();
  1939. }
  1940. NextChar();
  1941. }
  1942. if (textPos == textLen)
  1943. throw ParseError(textPos, SR.UnterminatedStringLiteral);
  1944. NextChar();
  1945. } while (ch == quote);
  1946. t = TokenId.StringLiteral;
  1947. break;
  1948. default:
  1949. if (IsIdentifierStart(ch) || ch == '@' || ch == '_')
  1950. {
  1951. do
  1952. {
  1953. NextChar();
  1954. } while (IsIdentifierPart(ch) || ch == '_');
  1955. t = TokenId.Identifier;
  1956. break;
  1957. }
  1958. if (Char.IsDigit(ch))
  1959. {
  1960. t = TokenId.IntegerLiteral;
  1961. do
  1962. {
  1963. NextChar();
  1964. } while (Char.IsDigit(ch));
  1965. if (ch == '.')
  1966. {
  1967. t = TokenId.RealLiteral;
  1968. NextChar();
  1969. ValidateDigit();
  1970. do
  1971. {
  1972. NextChar();
  1973. } while (Char.IsDigit(ch));
  1974. }
  1975. if (ch == 'E' || ch == 'e')
  1976. {
  1977. t = TokenId.RealLiteral;
  1978. NextChar();
  1979. if (ch == '+' || ch == '-')
  1980. NextChar();
  1981. ValidateDigit();
  1982. do
  1983. {
  1984. NextChar();
  1985. } while (Char.IsDigit(ch));
  1986. }
  1987. if (ch == 'F' || ch == 'f' || ch == 'M' || ch == 'm' || ch == 'D' || ch == 'd')
  1988. {
  1989. t = TokenId.RealLiteral;
  1990. NextChar();
  1991. }
  1992. break;
  1993. }
  1994. if (textPos == textLen)
  1995. {
  1996. t = TokenId.End;
  1997. break;
  1998. }
  1999. throw ParseError(textPos, SR.InvalidCharacter(ch));
  2000. }
  2001. token.id = t;
  2002. token.text = text.Substring(tokenPos, textPos - tokenPos);
  2003. token.pos = tokenPos;
  2004. token.id = ReclassifyToken(token);
  2005. }
  2006. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "Legacy code.")]
  2007. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Legacy code.")]
  2008. TokenId ReclassifyToken(Token token)
  2009. {
  2010. if (token.id == TokenId.Identifier)
  2011. {
  2012. if (token.text == "add")
  2013. {
  2014. return TokenId.Plus;
  2015. }
  2016. else if (token.text == "and")
  2017. {
  2018. return TokenId.DoubleAmphersand;
  2019. }
  2020. else if (token.text == "div")
  2021. {
  2022. return TokenId.Slash;
  2023. }
  2024. else if (token.text == "sub")
  2025. {
  2026. return TokenId.Minus;
  2027. }
  2028. else if (token.text == "mul")
  2029. {
  2030. return TokenId.Asterisk;
  2031. }
  2032. else if (token.text == "mod")
  2033. {
  2034. return TokenId.Percent;
  2035. }
  2036. else if (token.text == "ne")
  2037. {
  2038. return TokenId.ExclamationEqual;
  2039. }
  2040. else if (token.text == "not")
  2041. {
  2042. return TokenId.Exclamation;
  2043. }
  2044. else if (token.text == "le")
  2045. {
  2046. return TokenId.LessThanEqual;
  2047. }
  2048. else if (token.text == "lt")
  2049. {
  2050. return TokenId.LessThan;
  2051. }
  2052. else if (token.text == "eq")
  2053. {
  2054. return TokenId.DoubleEqual;
  2055. }
  2056. else if (token.text == "eq")
  2057. {
  2058. return TokenId.DoubleEqual;
  2059. }
  2060. else if (token.text == "ge")
  2061. {
  2062. return TokenId.GreaterThanEqual;
  2063. }
  2064. else if (token.text == "gt")
  2065. {
  2066. return TokenId.GreaterThan;
  2067. }
  2068. }
  2069. return token.id;
  2070. }
  2071. static bool IsIdentifierStart(char ch)
  2072. {
  2073. const int mask =
  2074. 1 << (int)UnicodeCategory.UppercaseLetter |
  2075. 1 << (int)UnicodeCategory.LowercaseLetter |
  2076. 1 << (int)UnicodeCategory.TitlecaseLetter |
  2077. 1 << (int)UnicodeCategory.ModifierLetter |
  2078. 1 << (int)UnicodeCategory.OtherLetter |
  2079. 1 << (int)UnicodeCategory.LetterNumber;
  2080. return (1 << (int)Char.GetUnicodeCategory(ch) & mask) != 0;
  2081. }
  2082. static bool IsIdentifierPart(char ch)
  2083. {
  2084. const int mask =
  2085. 1 << (int)UnicodeCategory.UppercaseLetter |
  2086. 1 << (int)UnicodeCategory.LowercaseLetter |
  2087. 1 << (int)UnicodeCategory.TitlecaseLetter |
  2088. 1 << (int)UnicodeCategory.ModifierLetter |
  2089. 1 << (int)UnicodeCategory.OtherLetter |
  2090. 1 << (int)UnicodeCategory.LetterNumber |
  2091. 1 << (int)UnicodeCategory.DecimalDigitNumber |
  2092. 1 << (int)UnicodeCategory.ConnectorPunctuation |
  2093. 1 << (int)UnicodeCategory.NonSpacingMark |
  2094. 1 << (int)UnicodeCategory.SpacingCombiningMark |
  2095. 1 << (int)UnicodeCategory.Format;
  2096. return (1 << (int)Char.GetUnicodeCategory(ch) & mask) != 0;
  2097. }
  2098. bool TokenIdentifierIs(string id)
  2099. {
  2100. return token.id == TokenId.Identifier && String.Equals(id, token.text, StringComparison.OrdinalIgnoreCase);
  2101. }
  2102. string GetIdentifier()
  2103. {
  2104. ValidateToken(TokenId.Identifier, SR.IdentifierExpected);
  2105. string id = token.text;
  2106. if (id.Length > 1 && id[0] == '@')
  2107. id = id.Substring(1);
  2108. return id;
  2109. }
  2110. void ValidateDigit()
  2111. {
  2112. if (!Char.IsDigit(ch))
  2113. throw ParseError(textPos, SR.DigitExpected);
  2114. }
  2115. void ValidateToken(TokenId t, string errorMessage)
  2116. {
  2117. if (token.id != t)
  2118. throw ParseError(errorMessage);
  2119. }
  2120. void ValidateToken(TokenId t)
  2121. {
  2122. if (token.id != t)
  2123. throw ParseError(SR.SyntaxError);
  2124. }
  2125. Exception ParseError(string format, params object[] args)
  2126. {
  2127. return ParseError(token.pos, format, args);
  2128. }
  2129. static Exception ParseError(int pos, string format, params object[] args)
  2130. {
  2131. return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos);
  2132. }
  2133. static Dictionary<string, object> CreateKeywords()
  2134. {
  2135. Dictionary<string, object> d = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  2136. d.Add("true", trueLiteral);
  2137. d.Add("false", falseLiteral);
  2138. d.Add("null", nullLiteral);
  2139. d.Add(keywordIt, keywordIt);
  2140. d.Add(keywordIif, keywordIif);
  2141. foreach (Type type in predefinedTypes)
  2142. d.Add(type.Name, type);
  2143. return d;
  2144. }
  2145. }
  2146. }