PageRenderTime 28ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Raven.Client.Lightweight/Indexes/ExpressionStringBuilder.cs

http://github.com/ravendb/ravendb
C# | 2285 lines | 1830 code | 204 blank | 251 comment | 363 complexity | 0d6ccb7154d59fef53d2aa93b3464f69 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause

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

  1. // //-----------------------------------------------------------------------
  2. // // <copyright company="Hibernating Rhinos LTD">
  3. // // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // // </copyright>
  5. // //-----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Dynamic;
  9. using System.Globalization;
  10. using System.Linq;
  11. using System.Linq.Expressions;
  12. using System.Reflection;
  13. using System.Runtime.CompilerServices;
  14. using System.Text;
  15. using Raven.Abstractions.Data;
  16. using Raven.Client.Document;
  17. using Raven.Imports.Newtonsoft.Json;
  18. using Raven.Client.Linq;
  19. using Raven.Imports.Newtonsoft.Json.Utilities;
  20. using Raven.Json.Linq;
  21. using Raven.Abstractions.Extensions;
  22. namespace Raven.Client.Indexes
  23. {
  24. /// <summary>
  25. /// Based off of System.Linq.Expressions.ExpressionStringBuilder
  26. /// </summary>
  27. public class ExpressionStringBuilder : ExpressionVisitor
  28. {
  29. // Fields
  30. private static readonly char[] LiteralSymbolsToEscape = new[] { '\'', '\"', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v' };
  31. private static readonly string[] LiteralEscapedSymbols = new[] { @"\'", @"\""", @"\\", @"\a", @"\b", @"\f", @"\n", @"\r", @"\t", @"\v" };
  32. private readonly StringBuilder _out = new StringBuilder();
  33. private readonly DocumentConvention convention;
  34. private readonly Type queryRoot;
  35. private readonly string queryRootName;
  36. private readonly bool translateIdentityProperty;
  37. private ExpressionOperatorPrecedence _currentPrecedence;
  38. private Dictionary<object, int> _ids;
  39. private Dictionary<string, object> _duplicatedParams = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
  40. private bool castLambdas;
  41. // Methods
  42. private ExpressionStringBuilder(DocumentConvention convention, bool translateIdentityProperty, Type queryRoot,
  43. string queryRootName)
  44. {
  45. this.convention = convention;
  46. this.translateIdentityProperty = translateIdentityProperty;
  47. this.queryRoot = queryRoot;
  48. this.queryRootName = queryRootName;
  49. }
  50. private int GetLabelId(LabelTarget label)
  51. {
  52. if (_ids == null)
  53. {
  54. _ids = new Dictionary<object, int> { { label, 0 } };
  55. }
  56. else if (!_ids.ContainsKey(label))
  57. {
  58. _ids.Add(label, _ids.Count);
  59. }
  60. return _ids.Count;
  61. }
  62. private void AddParam(ParameterExpression p)
  63. {
  64. if (_ids == null)
  65. {
  66. _ids = new Dictionary<object, int>();
  67. _ids.Add(_ids, 0);
  68. }
  69. else if (!_ids.ContainsKey(p))
  70. {
  71. _ids.Add(p, _ids.Count);
  72. }
  73. }
  74. internal string CatchBlockToString(CatchBlock node)
  75. {
  76. var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
  77. builder.VisitCatchBlock(node);
  78. return builder.ToString();
  79. }
  80. private void DumpLabel(LabelTarget target)
  81. {
  82. if (!string.IsNullOrEmpty(target.Name))
  83. {
  84. Out(target.Name);
  85. }
  86. else
  87. {
  88. Out("UnnamedLabel_" + GetLabelId(target));
  89. }
  90. }
  91. internal string ElementInitBindingToString(ElementInit node)
  92. {
  93. var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
  94. builder.VisitElementInit(node);
  95. return builder.ToString();
  96. }
  97. /// <summary>
  98. /// Convert the expression to a string
  99. /// </summary>
  100. public static string ExpressionToString(DocumentConvention convention, bool translateIdentityProperty, Type queryRoot,
  101. string queryRootName, Expression node)
  102. {
  103. var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
  104. builder.Visit(node, ExpressionOperatorPrecedence.ParenthesisNotNeeded);
  105. return builder.ToString();
  106. }
  107. private static string FormatBinder(CallSiteBinder binder)
  108. {
  109. var binder2 = binder as ConvertBinder;
  110. if (binder2 != null)
  111. {
  112. return ("Convert " + binder2.Type);
  113. }
  114. var binder3 = binder as GetMemberBinder;
  115. if (binder3 != null)
  116. {
  117. return ("GetMember " + binder3.Name);
  118. }
  119. var binder4 = binder as SetMemberBinder;
  120. if (binder4 != null)
  121. {
  122. return ("SetMember " + binder4.Name);
  123. }
  124. var binder5 = binder as DeleteMemberBinder;
  125. if (binder5 != null)
  126. {
  127. return ("DeleteMember " + binder5.Name);
  128. }
  129. if (binder is GetIndexBinder)
  130. {
  131. return "GetIndex";
  132. }
  133. if (binder is SetIndexBinder)
  134. {
  135. return "SetIndex";
  136. }
  137. if (binder is DeleteIndexBinder)
  138. {
  139. return "DeleteIndex";
  140. }
  141. var binder6 = binder as InvokeMemberBinder;
  142. if (binder6 != null)
  143. {
  144. return ("Call " + binder6.Name);
  145. }
  146. if (binder is InvokeBinder)
  147. {
  148. return "Invoke";
  149. }
  150. if (binder is CreateInstanceBinder)
  151. {
  152. return "Create";
  153. }
  154. var binder7 = binder as UnaryOperationBinder;
  155. if (binder7 != null)
  156. {
  157. return binder7.Operation.ToString();
  158. }
  159. var binder8 = binder as BinaryOperationBinder;
  160. if (binder8 != null)
  161. {
  162. return binder8.Operation.ToString();
  163. }
  164. return "CallSiteBinder";
  165. }
  166. private int GetParamId(ParameterExpression p)
  167. {
  168. int count;
  169. if (_ids == null)
  170. {
  171. _ids = new Dictionary<object, int>();
  172. AddParam(p);
  173. return 0;
  174. }
  175. if (!_ids.TryGetValue(p, out count))
  176. {
  177. count = _ids.Count;
  178. AddParam(p);
  179. }
  180. return count;
  181. }
  182. internal string MemberBindingToString(MemberBinding node)
  183. {
  184. var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
  185. builder.VisitMemberBinding(node);
  186. return builder.ToString();
  187. }
  188. private void Out(char c)
  189. {
  190. _out.Append(c);
  191. }
  192. private void Out(string s)
  193. {
  194. _out.Append(s);
  195. }
  196. private void OutMember(Expression instance, MemberInfo member, Type exprType)
  197. {
  198. bool isJsonProperty;
  199. var name = GetPropertyName(member.Name, exprType,out isJsonProperty);
  200. if (TranslateToDocumentId(instance, member, exprType))
  201. {
  202. name = Constants.DocumentIdFieldName;
  203. }
  204. if (instance != null)
  205. {
  206. if (ShouldParantesisMemberExpression(instance))
  207. Out("(");
  208. Visit(instance);
  209. if (ShouldParantesisMemberExpression(instance))
  210. Out(")");
  211. Out(isJsonProperty && !name.IsValidIdentifier() ?"[\"" + name +"\"]": "." + name);
  212. }
  213. else
  214. {
  215. var parentType = member.DeclaringType;
  216. while (parentType.IsNested)
  217. {
  218. parentType = parentType.DeclaringType;
  219. if (parentType == null)
  220. break;
  221. Out(parentType.Name + ".");
  222. }
  223. Out(member.DeclaringType.Name + "." + name);
  224. }
  225. }
  226. private static bool ShouldParantesisMemberExpression(Expression instance)
  227. {
  228. switch (instance.NodeType)
  229. {
  230. case ExpressionType.Parameter:
  231. case ExpressionType.MemberAccess:
  232. return false;
  233. default:
  234. return true;
  235. }
  236. }
  237. private bool TranslateToDocumentId(Expression instance, MemberInfo member, Type exprType)
  238. {
  239. if (translateIdentityProperty == false)
  240. return false;
  241. if (convention.GetIdentityProperty(member.DeclaringType) != member)
  242. return false;
  243. // only translate from the root type or derivatives
  244. if (queryRoot != null && (exprType.IsAssignableFrom(queryRoot) == false))
  245. return false;
  246. if (queryRootName == null)
  247. return true; // just in case, shouldn't really happen
  248. // only translate from the root alias
  249. string memberName = null;
  250. while (true)
  251. {
  252. switch (instance.NodeType)
  253. {
  254. case ExpressionType.MemberAccess:
  255. var memberExpression = ((MemberExpression)instance);
  256. if (memberName == null)
  257. {
  258. memberName = memberExpression.Member.Name;
  259. }
  260. instance = memberExpression.Expression;
  261. break;
  262. case ExpressionType.Parameter:
  263. var parameterExpression = ((ParameterExpression)instance);
  264. if (memberName == null)
  265. {
  266. memberName = parameterExpression.Name;
  267. }
  268. return memberName == queryRootName;
  269. default:
  270. return false;
  271. }
  272. }
  273. }
  274. private string GetPropertyName(string name, Type exprType,out bool isJsonProperty)
  275. {
  276. isJsonProperty = false;
  277. var memberInfo = (MemberInfo)exprType.GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) ??
  278. exprType.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  279. if (memberInfo == null)
  280. {
  281. memberInfo = ReflectionUtil.GetPropertiesAndFieldsFor(exprType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  282. .FirstOrDefault(x => x.Name == name);
  283. }
  284. if (memberInfo != null)
  285. {
  286. foreach (var customAttribute in memberInfo.GetCustomAttributes(true))
  287. {
  288. string propName;
  289. var customAttributeType = customAttribute.GetType();
  290. if (typeof(JsonPropertyAttribute).Namespace != customAttributeType.Namespace)
  291. continue;
  292. switch (customAttributeType.Name)
  293. {
  294. case "JsonPropertyAttribute":
  295. propName = ((dynamic)customAttribute).PropertyName;
  296. isJsonProperty = true;
  297. break;
  298. case "DataMemberAttribute":
  299. propName = ((dynamic)customAttribute).Name;
  300. break;
  301. default:
  302. continue;
  303. }
  304. if (keywordsInCSharp.Contains(propName))
  305. return '@' + propName;
  306. return propName ?? name;
  307. }
  308. }
  309. return name;
  310. }
  311. private static Type GetMemberType(MemberInfo member)
  312. {
  313. var prop = member as PropertyInfo;
  314. if (prop != null)
  315. return prop.PropertyType;
  316. return ((FieldInfo)member).FieldType;
  317. }
  318. internal string SwitchCaseToString(SwitchCase node)
  319. {
  320. var builder = new ExpressionStringBuilder(convention, translateIdentityProperty, queryRoot, queryRootName);
  321. builder.VisitSwitchCase(node);
  322. return builder.ToString();
  323. }
  324. /// <summary>
  325. /// Returns a <see cref = "System.String" /> that represents this instance.
  326. /// </summary>
  327. /// <returns>
  328. /// A <see cref = "System.String" /> that represents this instance.
  329. /// </returns>
  330. public override string ToString()
  331. {
  332. return _out.ToString();
  333. }
  334. private void SometimesParenthesis(ExpressionOperatorPrecedence outer, ExpressionOperatorPrecedence inner,
  335. Action visitor)
  336. {
  337. var needParenthesis = outer.NeedsParenthesisFor(inner);
  338. if (needParenthesis)
  339. Out("(");
  340. visitor();
  341. if (needParenthesis)
  342. Out(")");
  343. }
  344. private void Visit(Expression node, ExpressionOperatorPrecedence outerPrecedence)
  345. {
  346. var previous = _currentPrecedence;
  347. _currentPrecedence = outerPrecedence;
  348. Visit(node);
  349. _currentPrecedence = previous;
  350. }
  351. /// <summary>
  352. /// Visits the children of the <see cref = "T:System.Linq.Expressions.BinaryExpression" />.
  353. /// </summary>
  354. /// <param name = "node">The expression to visit.</param>
  355. /// <returns>
  356. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  357. /// </returns>
  358. protected override Expression VisitBinary(BinaryExpression node)
  359. {
  360. return VisitBinary(node, _currentPrecedence);
  361. }
  362. private Expression VisitBinary(BinaryExpression node, ExpressionOperatorPrecedence outerPrecedence)
  363. {
  364. ExpressionOperatorPrecedence innerPrecedence;
  365. string str;
  366. var leftOp = node.Left;
  367. var rightOp = node.Right;
  368. FixupEnumBinaryExpression(ref leftOp, ref rightOp);
  369. switch (node.NodeType)
  370. {
  371. case ExpressionType.Add:
  372. str = "+";
  373. innerPrecedence = ExpressionOperatorPrecedence.Additive;
  374. break;
  375. case ExpressionType.AddChecked:
  376. str = "+";
  377. innerPrecedence = ExpressionOperatorPrecedence.Additive;
  378. break;
  379. case ExpressionType.And:
  380. if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
  381. {
  382. str = "&";
  383. innerPrecedence = ExpressionOperatorPrecedence.LogicalAND;
  384. }
  385. else
  386. {
  387. str = "And";
  388. innerPrecedence = ExpressionOperatorPrecedence.ConditionalAND;
  389. }
  390. break;
  391. case ExpressionType.AndAlso:
  392. str = "&&";
  393. innerPrecedence = ExpressionOperatorPrecedence.ConditionalAND;
  394. break;
  395. case ExpressionType.Coalesce:
  396. str = "??";
  397. innerPrecedence = ExpressionOperatorPrecedence.NullCoalescing;
  398. break;
  399. case ExpressionType.Divide:
  400. str = "/";
  401. innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
  402. break;
  403. case ExpressionType.Equal:
  404. str = "==";
  405. innerPrecedence = ExpressionOperatorPrecedence.Equality;
  406. break;
  407. case ExpressionType.ExclusiveOr:
  408. str = "^";
  409. innerPrecedence = ExpressionOperatorPrecedence.LogicalXOR;
  410. break;
  411. case ExpressionType.GreaterThan:
  412. str = ">";
  413. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  414. break;
  415. case ExpressionType.GreaterThanOrEqual:
  416. str = ">=";
  417. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  418. break;
  419. case ExpressionType.LeftShift:
  420. str = "<<";
  421. innerPrecedence = ExpressionOperatorPrecedence.Shift;
  422. break;
  423. case ExpressionType.LessThan:
  424. str = "<";
  425. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  426. break;
  427. case ExpressionType.LessThanOrEqual:
  428. str = "<=";
  429. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  430. break;
  431. case ExpressionType.Modulo:
  432. str = "%";
  433. innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
  434. break;
  435. case ExpressionType.Multiply:
  436. str = "*";
  437. innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
  438. break;
  439. case ExpressionType.MultiplyChecked:
  440. str = "*";
  441. innerPrecedence = ExpressionOperatorPrecedence.Multiplicative;
  442. break;
  443. case ExpressionType.NotEqual:
  444. str = "!=";
  445. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  446. break;
  447. case ExpressionType.Or:
  448. if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
  449. {
  450. str = "|";
  451. innerPrecedence = ExpressionOperatorPrecedence.LogicalOR;
  452. }
  453. else
  454. {
  455. str = "Or";
  456. innerPrecedence = ExpressionOperatorPrecedence.LogicalOR;
  457. }
  458. break;
  459. case ExpressionType.OrElse:
  460. str = "||";
  461. innerPrecedence = ExpressionOperatorPrecedence.ConditionalOR;
  462. break;
  463. case ExpressionType.Power:
  464. str = "^";
  465. innerPrecedence = ExpressionOperatorPrecedence.LogicalXOR;
  466. break;
  467. case ExpressionType.RightShift:
  468. str = ">>";
  469. innerPrecedence = ExpressionOperatorPrecedence.Shift;
  470. break;
  471. case ExpressionType.Subtract:
  472. str = "-";
  473. innerPrecedence = ExpressionOperatorPrecedence.Additive;
  474. break;
  475. case ExpressionType.SubtractChecked:
  476. str = "-";
  477. innerPrecedence = ExpressionOperatorPrecedence.Additive;
  478. break;
  479. case ExpressionType.Assign:
  480. str = "=";
  481. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  482. break;
  483. case ExpressionType.AddAssign:
  484. str = "+=";
  485. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  486. break;
  487. case ExpressionType.AndAssign:
  488. if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
  489. {
  490. str = "&=";
  491. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  492. }
  493. else
  494. {
  495. str = "&&=";
  496. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  497. }
  498. break;
  499. case ExpressionType.DivideAssign:
  500. str = "/=";
  501. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  502. break;
  503. case ExpressionType.ExclusiveOrAssign:
  504. str = "^=";
  505. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  506. break;
  507. case ExpressionType.LeftShiftAssign:
  508. str = "<<=";
  509. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  510. break;
  511. case ExpressionType.ModuloAssign:
  512. str = "%=";
  513. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  514. break;
  515. case ExpressionType.MultiplyAssign:
  516. str = "*=";
  517. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  518. break;
  519. case ExpressionType.OrAssign:
  520. if ((node.Type != typeof(bool)) && (node.Type != typeof(bool?)))
  521. {
  522. str = "|=";
  523. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  524. }
  525. else
  526. {
  527. str = "||=";
  528. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  529. }
  530. break;
  531. case ExpressionType.PowerAssign:
  532. str = "**=";
  533. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  534. break;
  535. case ExpressionType.RightShiftAssign:
  536. str = ">>=";
  537. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  538. break;
  539. case ExpressionType.SubtractAssign:
  540. str = "-=";
  541. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  542. break;
  543. case ExpressionType.AddAssignChecked:
  544. str = "+=";
  545. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  546. break;
  547. case ExpressionType.MultiplyAssignChecked:
  548. str = "*=";
  549. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  550. break;
  551. case ExpressionType.SubtractAssignChecked:
  552. str = "-=";
  553. innerPrecedence = ExpressionOperatorPrecedence.Assignment;
  554. break;
  555. case ExpressionType.ArrayIndex:
  556. innerPrecedence = ExpressionOperatorPrecedence.Primary;
  557. SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
  558. {
  559. Visit(leftOp, innerPrecedence);
  560. Out("[");
  561. Visit(rightOp, innerPrecedence);
  562. Out("]");
  563. });
  564. return node;
  565. default:
  566. throw new InvalidOperationException();
  567. }
  568. SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
  569. {
  570. var needsCasting = (innerPrecedence == ExpressionOperatorPrecedence.NullCoalescing) && TypeExistsOnServer(rightOp.Type);
  571. if (needsCasting)
  572. {
  573. Out("((");
  574. Out(ConvertTypeToCSharpKeyword(rightOp.Type));
  575. Out(")(");
  576. }
  577. if (rightOp.NodeType == ExpressionType.Constant)
  578. {
  579. // on the server side, double is treated as decimal, so we have
  580. // to force this coercion so the constants would work
  581. if (rightOp.Type == typeof(double))
  582. {
  583. Out("(double?)");
  584. }
  585. else if (rightOp.Type == typeof(float))
  586. {
  587. Out("(float?)");
  588. }
  589. }
  590. Visit(leftOp, innerPrecedence);
  591. Out(' ');
  592. Out(str);
  593. Out(' ');
  594. Visit(rightOp, innerPrecedence);
  595. if (rightOp.NodeType == ExpressionType.Constant)
  596. {
  597. // on the server side, double is treated as decimal, so we have
  598. // to force this coercion so the constants would work
  599. if (rightOp.Type == typeof(double))
  600. {
  601. Out("D");
  602. }
  603. else if (rightOp.Type == typeof(float))
  604. {
  605. Out("F");
  606. }
  607. }
  608. if (needsCasting)
  609. {
  610. Out("))");
  611. }
  612. });
  613. return node;
  614. }
  615. private void FixupEnumBinaryExpression(ref Expression left, ref Expression right)
  616. {
  617. switch (left.NodeType)
  618. {
  619. case ExpressionType.ConvertChecked:
  620. case ExpressionType.Convert:
  621. var expression = ((UnaryExpression)left).Operand;
  622. var enumType = Nullable.GetUnderlyingType(expression.Type) ?? expression.Type;
  623. if (enumType.IsEnum() == false)
  624. return;
  625. var constantExpression = SkipConvertExpressions(right) as ConstantExpression;
  626. if (constantExpression == null)
  627. return;
  628. left = expression;
  629. if (constantExpression.Value == null)
  630. {
  631. right = Expression.Constant(null);
  632. }
  633. else
  634. {
  635. right = convention.SaveEnumsAsIntegers
  636. ? Expression.Constant(Convert.ToInt32(constantExpression.Value))
  637. : Expression.Constant(Enum.ToObject(enumType, constantExpression.Value).ToString());
  638. }
  639. break;
  640. }
  641. while (true)
  642. {
  643. switch (left.NodeType)
  644. {
  645. case ExpressionType.ConvertChecked:
  646. case ExpressionType.Convert:
  647. left = ((UnaryExpression)left).Operand;
  648. break;
  649. default:
  650. return;
  651. }
  652. }
  653. }
  654. private Expression SkipConvertExpressions(Expression expression)
  655. {
  656. switch (expression.NodeType)
  657. {
  658. case ExpressionType.ConvertChecked:
  659. case ExpressionType.Convert:
  660. return SkipConvertExpressions(((UnaryExpression)expression).Operand);
  661. default:
  662. return expression;
  663. }
  664. }
  665. /// <summary>
  666. /// Visits the children of the <see cref = "T:System.Linq.Expressions.BlockExpression" />.
  667. /// </summary>
  668. /// <param name = "node">The expression to visit.</param>
  669. /// <returns>
  670. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  671. /// </returns>
  672. protected override Expression VisitBlock(BlockExpression node)
  673. {
  674. Out("{");
  675. foreach (var expression in node.Variables)
  676. {
  677. Out("var ");
  678. Visit(expression);
  679. Out(";");
  680. }
  681. Out(" ... }");
  682. return node;
  683. }
  684. /// <summary>
  685. /// Visits the children of the <see cref = "T:System.Linq.Expressions.CatchBlock" />.
  686. /// </summary>
  687. /// <param name = "node">The expression to visit.</param>
  688. /// <returns>
  689. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  690. /// </returns>
  691. protected override CatchBlock VisitCatchBlock(CatchBlock node)
  692. {
  693. Out("catch (" + node.Test.Name);
  694. if (node.Variable != null)
  695. {
  696. Out(node.Variable.Name);
  697. }
  698. Out(") { ... }");
  699. return node;
  700. }
  701. /// <summary>
  702. /// Visits the children of the <see cref = "T:System.Linq.Expressions.ConditionalExpression" />.
  703. /// </summary>
  704. /// <param name = "node">The expression to visit.</param>
  705. /// <returns>
  706. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  707. /// </returns>
  708. protected override Expression VisitConditional(ConditionalExpression node)
  709. {
  710. return VisitConditional(node, _currentPrecedence);
  711. }
  712. private Expression VisitConditional(ConditionalExpression node, ExpressionOperatorPrecedence outerPrecedence)
  713. {
  714. const ExpressionOperatorPrecedence innerPrecedence = ExpressionOperatorPrecedence.Conditional;
  715. SometimesParenthesis(outerPrecedence, innerPrecedence, delegate
  716. {
  717. Visit(node.Test, innerPrecedence);
  718. Out(" ? ");
  719. Visit(node.IfTrue, innerPrecedence);
  720. Out(" : ");
  721. Visit(node.IfFalse, innerPrecedence);
  722. });
  723. return node;
  724. }
  725. /// <summary>
  726. /// Visits the <see cref = "T:System.Linq.Expressions.ConstantExpression" />.
  727. /// </summary>
  728. /// <param name = "node">The expression to visit.</param>
  729. /// <returns>
  730. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  731. /// </returns>
  732. protected override Expression VisitConstant(ConstantExpression node)
  733. {
  734. if (node.Value == null)
  735. {
  736. // Avoid converting/casting the type, if it already converted/casted.
  737. if (_currentPrecedence == ExpressionOperatorPrecedence.Assignment)
  738. ConvertTypeToCSharpKeywordIncludeNullable(node.Type);
  739. Out("null");
  740. return node;
  741. }
  742. var s = Convert.ToString(node.Value, CultureInfo.InvariantCulture);
  743. if (node.Value is string)
  744. {
  745. Out("\"");
  746. OutLiteral(node.Value as string);
  747. Out("\"");
  748. return node;
  749. }
  750. if (node.Value is bool)
  751. {
  752. Out(node.Value.ToString().ToLower());
  753. return node;
  754. }
  755. if (node.Value is char)
  756. {
  757. Out("'");
  758. OutLiteral((char)node.Value);
  759. Out("'");
  760. return node;
  761. }
  762. if (node.Value is Enum)
  763. {
  764. var enumType = node.Value.GetType();
  765. if (TypeExistsOnServer(enumType))
  766. {
  767. Out(enumType.FullName.Replace("+", "."));
  768. Out('.');
  769. Out(s);
  770. return node;
  771. }
  772. if (convention.SaveEnumsAsIntegers)
  773. Out((Convert.ToInt32(node.Value)).ToString());
  774. else
  775. {
  776. Out('"');
  777. Out(node.Value.ToString());
  778. Out('"');
  779. }
  780. return node;
  781. }
  782. if (node.Value is decimal)
  783. {
  784. Out(s);
  785. Out('M');
  786. return node;
  787. }
  788. Out(s);
  789. return node;
  790. }
  791. private void OutLiteral(string value)
  792. {
  793. if (value.Length == 0)
  794. return;
  795. _out.Append(string.Concat(value.ToCharArray().Select(EscapeChar)));
  796. }
  797. private void OutLiteral(char c)
  798. {
  799. _out.Append(EscapeChar(c));
  800. }
  801. private static string EscapeChar(char c)
  802. {
  803. var index = Array.IndexOf(LiteralSymbolsToEscape, c);
  804. if (index != -1)
  805. return LiteralEscapedSymbols[index];
  806. if (!char.IsLetterOrDigit(c) && !char.IsWhiteSpace(c) && !char.IsSymbol(c) && !char.IsPunctuation(c))
  807. return @"\u" + ((int)c).ToString("x4");
  808. #if !DNXCORE50
  809. return c.ToString(CultureInfo.InvariantCulture);
  810. #else
  811. return c.ToString();
  812. #endif
  813. }
  814. private void ConvertTypeToCSharpKeywordIncludeNullable(Type type)
  815. {
  816. var nonNullableType = Nullable.GetUnderlyingType(type);
  817. type = nonNullableType ?? type;
  818. var isNullableType = nonNullableType != null;
  819. // we only cast enums and types is mscorlib. We don't support anything else
  820. // because the VB compiler like to put converts all over the place, and include
  821. // types that we can't really support (only exists on the client)
  822. if (ShouldConvert(type) == false)
  823. return;
  824. Out("(");
  825. Out(ConvertTypeToCSharpKeyword(type));
  826. if (isNullableType && nonNullableType != typeof(Guid))
  827. {
  828. Out("?");
  829. }
  830. Out(")");
  831. }
  832. private string ConvertTypeToCSharpKeyword(Type type)
  833. {
  834. if (type.IsGenericType())
  835. {
  836. if (TypeExistsOnServer(type) == false)
  837. throw new InvalidOperationException("Cannot make use of type " + type + " because it is a generic type that doesn't exists on the server");
  838. var typeDefinition = type.GetGenericTypeDefinition();
  839. var sb = new StringBuilder(typeDefinition.FullName, 0)
  840. {
  841. Length = typeDefinition.FullName.IndexOf('`')
  842. };
  843. sb.Replace('+', '.');
  844. sb.Append("<");
  845. var arguments = type.GetGenericArguments();
  846. for (int i = 0; i < arguments.Length; i++)
  847. {
  848. if (i != 0)
  849. sb.Append(", ");
  850. sb.Append(ConvertTypeToCSharpKeyword(arguments[i]));
  851. }
  852. sb.Append(">");
  853. return sb.ToString();
  854. }
  855. if (type == typeof(string))
  856. {
  857. return "string";
  858. }
  859. if (type == typeof(Guid) || type == typeof(Guid?))
  860. {
  861. return "string"; // on the server, Guids are represented as strings
  862. }
  863. if (type == typeof(char))
  864. {
  865. return "char";
  866. }
  867. if (type == typeof(bool))
  868. {
  869. return "bool";
  870. }
  871. if (type == typeof(bool?))
  872. {
  873. return "bool?";
  874. }
  875. if (type == typeof(decimal))
  876. {
  877. return "decimal";
  878. }
  879. if (type == typeof(decimal?))
  880. {
  881. return "decimal?";
  882. }
  883. if (type == typeof(double))
  884. {
  885. return "double";
  886. }
  887. if (type == typeof(double?))
  888. {
  889. return "double?";
  890. }
  891. if (type == typeof(float))
  892. {
  893. return "float";
  894. }
  895. if (type == typeof(float?))
  896. {
  897. return "float?";
  898. }
  899. if (type == typeof(long))
  900. {
  901. return "long";
  902. }
  903. if (type == typeof(long?))
  904. {
  905. return "long?";
  906. }
  907. if (type == typeof(int))
  908. {
  909. return "int";
  910. }
  911. if (type == typeof(int?))
  912. {
  913. return "int?";
  914. }
  915. if (type == typeof(short))
  916. {
  917. return "short";
  918. }
  919. if (type == typeof(short?))
  920. {
  921. return "short?";
  922. }
  923. if (type == typeof(byte))
  924. {
  925. return "byte";
  926. }
  927. if (type == typeof(byte?))
  928. {
  929. return "byte?";
  930. }
  931. if (type.IsEnum())
  932. {
  933. return "string";
  934. }
  935. if (type.FullName == "System.Object")
  936. {
  937. return "object";
  938. }
  939. const string knownNamespace = "System";
  940. if (knownNamespace == type.Namespace)
  941. return type.Name;
  942. return type.FullName;
  943. }
  944. private bool TypeExistsOnServer(Type type)
  945. {
  946. if (type.Assembly() == typeof(object).Assembly()) // mscorlib
  947. return true;
  948. if (type.Assembly() == typeof(Uri).Assembly()) // System assembly
  949. return true;
  950. if (type.Assembly() == typeof(HashSet<>).Assembly()) // System.Core
  951. return true;
  952. if (type.Assembly() == typeof(RavenJObject).Assembly())
  953. return true;
  954. if (type.Assembly().FullName.StartsWith("Lucene.Net") &&
  955. type.Assembly().FullName.Contains("PublicKeyToken=85089178b9ac3181"))
  956. return true;
  957. return false;
  958. }
  959. /// <summary>
  960. /// Visits the <see cref = "T:System.Linq.Expressions.DebugInfoExpression" />.
  961. /// </summary>
  962. /// <param name = "node">The expression to visit.</param>
  963. /// <returns>
  964. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  965. /// </returns>
  966. protected override Expression VisitDebugInfo(DebugInfoExpression node)
  967. {
  968. var s = string.Format(CultureInfo.CurrentCulture, "<DebugInfo({0}: {1}, {2}, {3}, {4})>",
  969. new object[] { node.Document.FileName, node.StartLine, node.StartColumn, node.EndLine, node.EndColumn });
  970. Out(s);
  971. return node;
  972. }
  973. /// <summary>
  974. /// Visits the <see cref = "T:System.Linq.Expressions.DefaultExpression" />.
  975. /// </summary>
  976. /// <param name = "node">The expression to visit.</param>
  977. /// <returns>
  978. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  979. /// </returns>
  980. protected override Expression VisitDefault(DefaultExpression node)
  981. {
  982. Out("default(");
  983. var nonNullable = Nullable.GetUnderlyingType(node.Type);
  984. Out(ConvertTypeToCSharpKeyword(nonNullable ?? node.Type));
  985. if (nonNullable != null && nonNullable != typeof(Guid))
  986. Out("?");
  987. Out(")");
  988. return node;
  989. }
  990. #if !DNXCORE50
  991. /// <summary>
  992. /// Visits the children of the <see cref = "T:System.Linq.Expressions.DynamicExpression" />.
  993. /// </summary>
  994. /// <param name = "node">The expression to visit.</param>
  995. /// <returns>
  996. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  997. /// </returns>
  998. protected override Expression VisitDynamic(DynamicExpression node)
  999. {
  1000. Out(FormatBinder(node.Binder));
  1001. VisitExpressions('(', node.Arguments, ')');
  1002. return node;
  1003. }
  1004. #endif
  1005. /// <summary>
  1006. /// Visits the element init.
  1007. /// </summary>
  1008. /// <param name = "initializer">The initializer.</param>
  1009. /// <returns></returns>
  1010. protected override ElementInit VisitElementInit(ElementInit initializer)
  1011. {
  1012. Out(initializer.AddMethod.ToString());
  1013. VisitExpressions('(', initializer.Arguments, ')');
  1014. return initializer;
  1015. }
  1016. private void VisitExpressions<T>(char open, IEnumerable<T> expressions, char close) where T : Expression
  1017. {
  1018. Out(open);
  1019. if (expressions != null)
  1020. {
  1021. var flag = true;
  1022. foreach (var local in expressions)
  1023. {
  1024. if (flag)
  1025. {
  1026. flag = false;
  1027. }
  1028. else
  1029. {
  1030. Out(", ");
  1031. }
  1032. Visit(local, ExpressionOperatorPrecedence.ParenthesisNotNeeded);
  1033. }
  1034. }
  1035. Out(close);
  1036. }
  1037. /// <summary>
  1038. /// Visits the children of the extension expression.
  1039. /// </summary>
  1040. /// <param name = "node">The expression to visit.</param>
  1041. /// <returns>
  1042. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1043. /// </returns>
  1044. protected override Expression VisitExtension(Expression node)
  1045. {
  1046. #if !DNXCORE50
  1047. const BindingFlags bindingAttr = BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance;
  1048. #else
  1049. const BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance;
  1050. #endif
  1051. if (node.GetType().GetMethod("ToString", bindingAttr, null, ReflectionUtils.EmptyTypes, null).DeclaringType !=
  1052. typeof(Expression))
  1053. {
  1054. Out(node.ToString());
  1055. return node;
  1056. }
  1057. Out("[");
  1058. Out(node.NodeType == ExpressionType.Extension ? node.GetType().FullName : node.NodeType.ToString());
  1059. Out("]");
  1060. return node;
  1061. }
  1062. /// <summary>
  1063. /// Visits the children of the <see cref = "T:System.Linq.Expressions.GotoExpression" />.
  1064. /// </summary>
  1065. /// <param name = "node">The expression to visit.</param>
  1066. /// <returns>
  1067. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1068. /// </returns>
  1069. protected override Expression VisitGoto(GotoExpression node)
  1070. {
  1071. #if !DNXCORE50
  1072. Out(node.Kind.ToString().ToLower(CultureInfo.CurrentCulture));
  1073. #else
  1074. Out(node.Kind.ToString().ToLower());
  1075. #endif
  1076. DumpLabel(node.Target);
  1077. if (node.Value != null)
  1078. {
  1079. Out(" (");
  1080. Visit(node.Value);
  1081. Out(") ");
  1082. }
  1083. return node;
  1084. }
  1085. /// <summary>
  1086. /// Visits the children of the <see cref = "T:System.Linq.Expressions.IndexExpression" />.
  1087. /// </summary>
  1088. /// <param name = "node">The expression to visit.</param>
  1089. /// <returns>
  1090. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1091. /// </returns>
  1092. protected override Expression VisitIndex(IndexExpression node)
  1093. {
  1094. if (node.Object != null)
  1095. {
  1096. Visit(node.Object);
  1097. }
  1098. else
  1099. {
  1100. Out(node.Indexer.DeclaringType.Name);
  1101. }
  1102. if (node.Indexer != null)
  1103. {
  1104. Out(".");
  1105. Out(node.Indexer.Name);
  1106. }
  1107. VisitExpressions('[', node.Arguments, ']');
  1108. return node;
  1109. }
  1110. /// <summary>
  1111. /// Visits the children of the <see cref = "T:System.Linq.Expressions.InvocationExpression" />.
  1112. /// </summary>
  1113. /// <param name = "node">The expression to visit.</param>
  1114. /// <returns>
  1115. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1116. /// </returns>
  1117. protected override Expression VisitInvocation(InvocationExpression node)
  1118. {
  1119. Out("Invoke(");
  1120. Visit(node.Expression);
  1121. var num = 0;
  1122. var count = node.Arguments.Count;
  1123. while (num < count)
  1124. {
  1125. Out(", ");
  1126. Visit(node.Arguments[num]);
  1127. num++;
  1128. }
  1129. Out(")");
  1130. return node;
  1131. }
  1132. /// <summary>
  1133. /// Visits the children of the <see cref = "T:System.Linq.Expressions.LabelExpression" />.
  1134. /// </summary>
  1135. /// <param name = "node">The expression to visit.</param>
  1136. /// <returns>
  1137. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1138. /// </returns>
  1139. protected override Expression VisitLabel(LabelExpression node)
  1140. {
  1141. Out("{ ... } ");
  1142. DumpLabel(node.Target);
  1143. Out(":");
  1144. return node;
  1145. }
  1146. /// <summary>
  1147. /// Visits the lambda.
  1148. /// </summary>
  1149. /// <typeparam name = "T"></typeparam>
  1150. /// <param name = "node">The node.</param>
  1151. /// <returns></returns>
  1152. protected override Expression VisitLambda<T>(Expression<T> node)
  1153. {
  1154. if (node.Parameters.Count == 1)
  1155. {
  1156. Visit(node.Parameters[0]);
  1157. }
  1158. else
  1159. {
  1160. VisitExpressions('(', node.Parameters, ')');
  1161. }
  1162. Out(" => ");
  1163. var body = node.Body;
  1164. if (castLambdas)
  1165. {
  1166. switch (body.NodeType)
  1167. {
  1168. case ExpressionType.Convert:
  1169. case ExpressionType.ConvertChecked:
  1170. break;
  1171. default:
  1172. body = Expression.Convert(body, body.Type);
  1173. break;
  1174. }
  1175. }
  1176. Visit(body);
  1177. return node;
  1178. }
  1179. /// <summary>
  1180. /// Visits the children of the <see cref = "T:System.Linq.Expressions.ListInitExpression" />.
  1181. /// </summary>
  1182. /// <param name = "node">The expression to visit.</param>
  1183. /// <returns>
  1184. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1185. /// </returns>
  1186. protected override Expression VisitListInit(ListInitExpression node)
  1187. {
  1188. Visit(node.NewExpression);
  1189. Out(" {");
  1190. var num = 0;
  1191. var count = node.Initializers.Count;
  1192. while (num < count)
  1193. {
  1194. if (num > 0)
  1195. {
  1196. Out(", ");
  1197. }
  1198. Out("{");
  1199. bool first = true;
  1200. foreach (var expression in node.Initializers[num].Arguments)
  1201. {
  1202. if (first == false)
  1203. Out(", ");
  1204. first = false;
  1205. Visit(expression);
  1206. }
  1207. Out("}");
  1208. num++;
  1209. }
  1210. Out("}");
  1211. return node;
  1212. }
  1213. /// <summary>
  1214. /// Visits the children of the <see cref = "T:System.Linq.Expressions.LoopExpression" />.
  1215. /// </summary>
  1216. /// <param name = "node">The expression to visit.</param>
  1217. /// <returns>
  1218. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1219. /// </returns>
  1220. protected override Expression VisitLoop(LoopExpression node)
  1221. {
  1222. Out("loop { ... }");
  1223. return node;
  1224. }
  1225. /// <summary>
  1226. /// Visits the children of the <see cref = "T:System.Linq.Expressions.MemberExpression" />.
  1227. /// </summary>
  1228. /// <pa…

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