PageRenderTime 57ms CodeModel.GetById 17ms 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
  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. /// <param name = "node">The expression to visit.</param>
  1229. /// <returns>
  1230. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1231. /// </returns>
  1232. protected override Expression VisitMember(MemberExpression node)
  1233. {
  1234. if (Nullable.GetUnderlyingType(node.Member.DeclaringType) != null)
  1235. {
  1236. switch (node.Member.Name)
  1237. {
  1238. case "HasValue":
  1239. // we don't have nullable type on the server side, we just compare to null
  1240. Out("(");
  1241. Visit(node.Expression);
  1242. Out(" != null)");
  1243. return node;
  1244. case "Value":
  1245. Visit(node.Expression);
  1246. return node; // we don't have nullable type on the server side, we can safely ignore this.
  1247. }
  1248. }
  1249. var exprType = node.Expression != null ? node.Member.DeclaringType : node.Type;
  1250. OutMember(node.Expression, node.Member, exprType);
  1251. return node;
  1252. }
  1253. /// <summary>
  1254. /// Visits the member assignment.
  1255. /// </summary>
  1256. /// <param name = "assignment">The assignment.</param>
  1257. /// <returns></returns>
  1258. protected override MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
  1259. {
  1260. Out(assignment.Member.Name);
  1261. Out(" = ");
  1262. var constantExpression = assignment.Expression as ConstantExpression;
  1263. if (constantExpression != null && constantExpression.Value == null)
  1264. {
  1265. var memberType = GetMemberType(assignment.Member);
  1266. if (ShouldConvert(memberType))
  1267. {
  1268. Visit(Expression.Convert(assignment.Expression, memberType));
  1269. }
  1270. else
  1271. {
  1272. Out("(object)null");
  1273. }
  1274. return assignment;
  1275. }
  1276. Visit(assignment.Expression);
  1277. return assignment;
  1278. }
  1279. /// <summary>
  1280. /// Visits the children of the <see cref = "T:System.Linq.Expressions.MemberInitExpression" />.
  1281. /// </summary>
  1282. /// <param name = "node">The expression to visit.</param>
  1283. /// <returns>
  1284. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1285. /// </returns>
  1286. protected override Expression VisitMemberInit(MemberInitExpression node)
  1287. {
  1288. if ((node.NewExpression.Arguments.Count == 0) && node.NewExpression.Type.Name.Contains("<"))
  1289. {
  1290. Out("new");
  1291. }
  1292. else
  1293. {
  1294. Visit(node.NewExpression);
  1295. if (TypeExistsOnServer(node.Type) == false)
  1296. {
  1297. const int removeLength = 2;
  1298. _out.Remove(_out.Length - removeLength, removeLength);
  1299. }
  1300. }
  1301. Out(" {");
  1302. var num = 0;
  1303. var count = node.Bindings.Count;
  1304. while (num < count)
  1305. {
  1306. var binding = node.Bindings[num];
  1307. if (num > 0)
  1308. {
  1309. Out(", ");
  1310. }
  1311. VisitMemberBinding(binding);
  1312. num++;
  1313. }
  1314. Out("}");
  1315. return node;
  1316. }
  1317. /// <summary>
  1318. /// Visits the member list binding.
  1319. /// </summary>
  1320. /// <param name = "binding">The binding.</param>
  1321. /// <returns></returns>
  1322. protected override MemberListBinding VisitMemberListBinding(MemberListBinding binding)
  1323. {
  1324. Out(binding.Member.Name);
  1325. Out(" = {");
  1326. var num = 0;
  1327. var count = binding.Initializers.Count;
  1328. while (num < count)
  1329. {
  1330. if (num > 0)
  1331. {
  1332. Out(", ");
  1333. }
  1334. VisitElementInit(binding.Initializers[num]);
  1335. num++;
  1336. }
  1337. Out("}");
  1338. return binding;
  1339. }
  1340. /// <summary>
  1341. /// Visits the member member binding.
  1342. /// </summary>
  1343. /// <param name = "binding">The binding.</param>
  1344. /// <returns></returns>
  1345. protected override MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
  1346. {
  1347. Out(binding.Member.Name);
  1348. Out(" = {");
  1349. var num = 0;
  1350. var count = binding.Bindings.Count;
  1351. while (num < count)
  1352. {
  1353. if (num > 0)
  1354. {
  1355. Out(", ");
  1356. }
  1357. VisitMemberBinding(binding.Bindings[num]);
  1358. num++;
  1359. }
  1360. Out("}");
  1361. return binding;
  1362. }
  1363. /// <summary>
  1364. /// Visits the children of the <see cref = "T:System.Linq.Expressions.MethodCallExpression" />.
  1365. /// </summary>
  1366. /// <param name = "node">The expression to visit.</param>
  1367. /// <returns>
  1368. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1369. /// </returns>
  1370. protected override Expression VisitMethodCall(MethodCallExpression node)
  1371. {
  1372. var constantExpression = node.Object as ConstantExpression;
  1373. if (constantExpression != null && node.Type == typeof(Delegate))
  1374. {
  1375. var methodInfo = constantExpression.Value as MethodInfo;
  1376. if (methodInfo != null && methodInfo.DeclaringType == typeof(AbstractCommonApiForIndexesAndTransformers))// a delegate call
  1377. {
  1378. Out("((Func<");
  1379. for (int i = 0; i < methodInfo.GetParameters().Length; i++)
  1380. {
  1381. Out("dynamic, ");
  1382. }
  1383. Out("dynamic>)(");
  1384. Out(methodInfo.Name);
  1385. Out("))");
  1386. return node;
  1387. }
  1388. }
  1389. if (node.Method.Name == "GetValueOrDefault" && Nullable.GetUnderlyingType(node.Method.DeclaringType) != null)
  1390. {
  1391. Visit(node.Object);
  1392. return node; // we don't do anything here on the server
  1393. }
  1394. var num = 0;
  1395. var expression = node.Object;
  1396. if (IsExtensionMethod(node))
  1397. {
  1398. num = 1;
  1399. expression = node.Arguments[0];
  1400. }
  1401. if (expression != null)
  1402. {
  1403. switch (node.Method.Name)
  1404. {
  1405. case "MetadataFor":
  1406. Visit(node.Arguments[0]);
  1407. Out("[\"@metadata\"]");
  1408. return node;
  1409. case "AsDocument":
  1410. Visit(node.Arguments[0]);
  1411. return node;
  1412. }
  1413. if (expression.Type == typeof(IClientSideDatabase))
  1414. {
  1415. Out("Database");
  1416. }
  1417. else if (typeof(AbstractCommonApiForIndexesAndTransformers).IsAssignableFrom(expression.Type))
  1418. {
  1419. // this is a method that
  1420. // exists on both the server side and the client side
  1421. Out("this");
  1422. }
  1423. else
  1424. {
  1425. Visit(expression);
  1426. }
  1427. if (IsIndexerCall(node) == false)
  1428. {
  1429. Out(".");
  1430. }
  1431. }
  1432. if (node.Method.IsStatic && ShouldConvertToDynamicEnumerable(node))
  1433. {
  1434. Out("DynamicEnumerable.");
  1435. }
  1436. else if (node.Method.IsStatic && IsExtensionMethod(node) == false)
  1437. {
  1438. if (node.Method.DeclaringType == typeof(Enumerable) && node.Method.Name == "Cast")
  1439. {
  1440. Out("new Raven.Abstractions.Linq.DynamicList(");
  1441. Visit(node.Arguments[0]);
  1442. Out(")");
  1443. return node; // we don't do casting on the server
  1444. }
  1445. Out(node.Method.DeclaringType.Name);
  1446. Out(".");
  1447. }
  1448. if (IsIndexerCall(node))
  1449. {
  1450. Out("[");
  1451. }
  1452. else
  1453. {
  1454. switch (node.Method.Name)
  1455. {
  1456. case "First":
  1457. Out("FirstOrDefault");
  1458. break;
  1459. case "Last":
  1460. Out("LastOrDefault");
  1461. break;
  1462. case "Single":
  1463. Out("SingleOrDefault");
  1464. break;
  1465. case "ElementAt":
  1466. Out("ElementAtOrDefault");
  1467. break;
  1468. // Convert OfType<Foo>() to Where(x => x["$type"] == typeof(Foo).AssemblyQualifiedName)
  1469. case "OfType":
  1470. Out("Where");
  1471. break;
  1472. default:
  1473. Out(node.Method.Name);
  1474. if (node.Method.IsGenericMethod)
  1475. {
  1476. OutputGenericMethodArgumentsIfNeeded(node.Method);
  1477. }
  1478. break;
  1479. }
  1480. Out("(");
  1481. }
  1482. var num2 = num;
  1483. var count = node.Arguments.Count;
  1484. while (num2 < count)
  1485. {
  1486. if (num2 > num)
  1487. {
  1488. Out(", ");
  1489. }
  1490. var old = castLambdas;
  1491. try
  1492. {
  1493. switch (node.Method.Name)
  1494. {
  1495. case "Sum":
  1496. case "Average":
  1497. case "Min":
  1498. case "Max":
  1499. castLambdas = true;
  1500. break;
  1501. default:
  1502. castLambdas = false;
  1503. break;
  1504. }
  1505. var oldAvoidDuplicateParameters = _avoidDuplicatedParameters;
  1506. if (node.Method.Name == "Select")
  1507. {
  1508. _avoidDuplicatedParameters = true;
  1509. }
  1510. Visit(node.Arguments[num2]);
  1511. _avoidDuplicatedParameters = oldAvoidDuplicateParameters;
  1512. // Convert OfType<Foo>() to Where(x => x["$type"] == typeof(Foo).AssemblyQualifiedName)
  1513. if (node.Method.Name == "OfType")
  1514. {
  1515. var type = node.Method.GetGenericArguments()[0];
  1516. var typeFullName = ReflectionUtil.GetFullNameWithoutVersionInformation(type);
  1517. Out(", (Func<dynamic, bool>)(_itemRaven => string.Equals(_itemRaven[\"$type\"], \"");
  1518. Out(typeFullName);
  1519. Out("\", StringComparison.Ordinal))");
  1520. }
  1521. }
  1522. finally
  1523. {
  1524. castLambdas = old;
  1525. }
  1526. num2++;
  1527. }
  1528. Out(IsIndexerCall(node) ? "]" : ")");
  1529. if (node.Type.IsValueType() && TypeExistsOnServer(node.Type))
  1530. {
  1531. switch (node.Method.Name)
  1532. {
  1533. case "First":
  1534. case "FirstOrDefault":
  1535. case "Last":
  1536. case "LastOrDefault":
  1537. case "Single":
  1538. case "SingleOrDefault":
  1539. case "ElementAt":
  1540. case "ElementAtOrDefault":
  1541. Out(" ?? ");
  1542. VisitDefault(Expression.Default(node.Type));
  1543. break;
  1544. }
  1545. }
  1546. return node;
  1547. }
  1548. private void OutputGenericMethodArgumentsIfNeeded(MethodInfo method)
  1549. {
  1550. var genericArguments = method.GetGenericArguments();
  1551. if (genericArguments.All(TypeExistsOnServer) == false)
  1552. return; // no point if the types aren't on the server
  1553. switch (method.DeclaringType.Name)
  1554. {
  1555. case "Enumerable":
  1556. case "Queryable":
  1557. return; // we don't need those, we have LinqOnDynamic for it
  1558. }
  1559. Out("<");
  1560. bool first = true;
  1561. foreach (var genericArgument in genericArguments)
  1562. {
  1563. if (first == false)
  1564. {
  1565. Out(", ");
  1566. }
  1567. first = false;
  1568. VisitType(genericArgument);
  1569. }
  1570. Out(">");
  1571. }
  1572. private static bool IsIndexerCall(MethodCallExpression node)
  1573. {
  1574. return node.Method.IsSpecialName && (node.Method.Name.StartsWith("get_") || node.Method.Name.StartsWith("set_"));
  1575. }
  1576. private static bool ShouldConvertToDynamicEnumerable(MethodCallExpression node)
  1577. {
  1578. if (node.Method.DeclaringType.Name == "Enumerable")
  1579. {
  1580. switch (node.Method.Name)
  1581. {
  1582. case "First":
  1583. case "FirstOrDefault":
  1584. case "Single":
  1585. case "SingleOrDefault":
  1586. case "Last":
  1587. case "LastOrDefault":
  1588. case "ElementAt":
  1589. case "ElementAtOrDefault":
  1590. case "Min":
  1591. case "Max":
  1592. case "Union":
  1593. case "Concat":
  1594. case "Intersect":
  1595. return true;
  1596. }
  1597. }
  1598. return false;
  1599. }
  1600. private static bool IsExtensionMethod(MethodCallExpression node)
  1601. {
  1602. var attribute = node.Method.GetCustomAttribute(typeof(ExtensionAttribute));
  1603. if (attribute == null)
  1604. return false;
  1605. if (node.Method.DeclaringType.Name == "Enumerable")
  1606. {
  1607. switch (node.Method.Name)
  1608. {
  1609. case "Select":
  1610. case "SelectMany":
  1611. case "Where":
  1612. case "GroupBy":
  1613. case "OrderBy":
  1614. case "OrderByDescending":
  1615. case "DefaultIfEmpty":
  1616. case "Reverse":
  1617. case "Take":
  1618. case "Skip":
  1619. return true;
  1620. }
  1621. return false;
  1622. }
  1623. if (node.Method.GetCustomAttributes(typeof(RavenMethodAttribute), false).Count() != 0)
  1624. return false;
  1625. return true;
  1626. }
  1627. /// <summary>
  1628. /// Visits the children of the <see cref = "T:System.Linq.Expressions.NewExpression" />.
  1629. /// </summary>
  1630. /// <param name = "node">The expression to visit.</param>
  1631. /// <returns>
  1632. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1633. /// </returns>
  1634. protected override Expression VisitNew(NewExpression node)
  1635. {
  1636. Out("new ");
  1637. if (TypeExistsOnServer(node.Type))
  1638. {
  1639. VisitType(node.Type);
  1640. Out("(");
  1641. }
  1642. else
  1643. {
  1644. Out("{");
  1645. }
  1646. for (var i = 0; i < node.Arguments.Count; i++)
  1647. {
  1648. if (i > 0)
  1649. {
  1650. Out(", ");
  1651. }
  1652. if (node.Members != null && node.Members[i] != null)
  1653. {
  1654. Out(node.Members[i].Name);
  1655. Out(" = ");
  1656. var constantExpression = node.Arguments[i] as ConstantExpression;
  1657. if (constantExpression != null && constantExpression.Value == null)
  1658. {
  1659. Out("(");
  1660. VisitType(GetMemberType(node.Members[i]));
  1661. Out(")");
  1662. }
  1663. }
  1664. Visit(node.Arguments[i]);
  1665. }
  1666. if (TypeExistsOnServer(node.Type))
  1667. {
  1668. Out(")");
  1669. }
  1670. else
  1671. {
  1672. Out("}");
  1673. }
  1674. return node;
  1675. }
  1676. private void VisitType(Type type)
  1677. {
  1678. if (type.IsGenericType() == false || CheckIfAnonymousType(type))
  1679. {
  1680. if (type.IsArray)
  1681. {
  1682. VisitType(type.GetElementType());
  1683. Out("[");
  1684. for (int i = 0; i < type.GetArrayRank() - 1; i++)
  1685. {
  1686. Out(",");
  1687. }
  1688. Out("]");
  1689. return;
  1690. }
  1691. var nonNullableType = Nullable.GetUnderlyingType(type);
  1692. if (nonNullableType != null)
  1693. {
  1694. VisitType(nonNullableType);
  1695. Out("?");
  1696. return;
  1697. }
  1698. Out(ConvertTypeToCSharpKeyword(type));
  1699. return;
  1700. }
  1701. var genericArguments = type.GetGenericArguments();
  1702. var genericTypeDefinition = type.GetGenericTypeDefinition();
  1703. var lastIndexOfTag = genericTypeDefinition.FullName.LastIndexOf('`');
  1704. Out(genericTypeDefinition.FullName.Substring(0, lastIndexOfTag));
  1705. Out("<");
  1706. bool first = true;
  1707. foreach (var genericArgument in genericArguments)
  1708. {
  1709. if (first == false)
  1710. Out(", ");
  1711. first = false;
  1712. VisitType(genericArgument);
  1713. }
  1714. Out(">");
  1715. }
  1716. /// <summary>
  1717. /// Visits the children of the <see cref = "T:System.Linq.Expressions.NewArrayExpression" />.
  1718. /// </summary>
  1719. /// <param name = "node">The expression to visit.</param>
  1720. /// <returns>
  1721. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1722. /// </returns>
  1723. protected override Expression VisitNewArray(NewArrayExpression node)
  1724. {
  1725. switch (node.NodeType)
  1726. {
  1727. case ExpressionType.NewArrayInit:
  1728. Out("new ");
  1729. if (!CheckIfAnonymousType(node.Type.GetElementType()) && TypeExistsOnServer(node.Type.GetElementType()))
  1730. {
  1731. Out(ConvertTypeToCSharpKeyword(node.Type.GetElementType()));
  1732. }
  1733. else if (node.Expressions.Count == 0)
  1734. {
  1735. Out("object");
  1736. }
  1737. Out("[]");
  1738. VisitExpressions('{', node.Expressions, '}');
  1739. return node;
  1740. case ExpressionType.NewArrayBounds:
  1741. if(TypeExistsOnServer(node.Type))
  1742. Out("new " + node.Type.GetElementType());
  1743. else
  1744. Out("new object");
  1745. VisitExpressions('[', node.Expressions, ']');
  1746. return node;
  1747. }
  1748. return node;
  1749. }
  1750. private static bool CheckIfAnonymousType(Type type)
  1751. {
  1752. // hack: the only way to detect anonymous types right now
  1753. return type.IsDefined(typeof(CompilerGeneratedAttribute), false)
  1754. && type.IsGenericType() && type.Name.Contains("AnonymousType")
  1755. && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
  1756. && type.GetTypeInfo().Attributes.HasFlag(TypeAttributes.NotPublic);
  1757. }
  1758. public static readonly HashSet<string> keywordsInCSharp = new HashSet<string>(new[]
  1759. {
  1760. "abstract",
  1761. "as",
  1762. "base",
  1763. "bool",
  1764. "break",
  1765. "byte",
  1766. "case",
  1767. "catch",
  1768. "char",
  1769. "checked",
  1770. "class",
  1771. "const",
  1772. "continue",
  1773. "decimal",
  1774. "default",
  1775. "delegate",
  1776. "do",
  1777. "double",
  1778. "else",
  1779. "enum",
  1780. "event",
  1781. "explicit",
  1782. "extern",
  1783. "false",
  1784. "finally",
  1785. "fixed",
  1786. "float",
  1787. "for",
  1788. "foreach",
  1789. "goto",
  1790. "if",
  1791. "implicit",
  1792. "in",
  1793. "in (generic modifier)",
  1794. "int",
  1795. "interface",
  1796. "internal",
  1797. "is",
  1798. "lock",
  1799. "long",
  1800. "namespace",
  1801. "new",
  1802. "null",
  1803. "object",
  1804. "operator",
  1805. "out",
  1806. "out (generic modifier)",
  1807. "override",
  1808. "params",
  1809. "private",
  1810. "protected",
  1811. "public",
  1812. "readonly",
  1813. "ref",
  1814. "return",
  1815. "sbyte",
  1816. "sealed",
  1817. "short",
  1818. "sizeof",
  1819. "stackalloc",
  1820. "static",
  1821. "string",
  1822. "struct",
  1823. "switch",
  1824. "this",
  1825. "throw",
  1826. "true",
  1827. "try",
  1828. "typeof",
  1829. "uint",
  1830. "ulong",
  1831. "unchecked",
  1832. "unsafe",
  1833. "ushort",
  1834. "using",
  1835. "virtual",
  1836. "void",
  1837. "volatile",
  1838. "while"
  1839. });
  1840. private bool _avoidDuplicatedParameters;
  1841. /// <summary>
  1842. /// Visits the <see cref = "T:System.Linq.Expressions.ParameterExpression" />.
  1843. /// </summary>
  1844. /// <param name = "node">The expression to visit.</param>
  1845. /// <returns>
  1846. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1847. /// </returns>
  1848. protected override Expression VisitParameter(ParameterExpression node)
  1849. {
  1850. if (node.IsByRef)
  1851. {
  1852. Out("ref ");
  1853. }
  1854. if (string.IsNullOrEmpty(node.Name))
  1855. {
  1856. Out("Param_" + GetParamId(node));
  1857. return node;
  1858. }
  1859. var name = node.Name;
  1860. if (_avoidDuplicatedParameters)
  1861. {
  1862. object other;
  1863. if (_duplicatedParams.TryGetValue(name, out other) && ReferenceEquals(other, node) == false)
  1864. {
  1865. name += GetParamId(node);
  1866. _duplicatedParams[name] = node;
  1867. }
  1868. else
  1869. {
  1870. _duplicatedParams[name] = node;
  1871. }
  1872. }
  1873. name = name.StartsWith("$VB$") ? name.Substring(4) : name;
  1874. if (keywordsInCSharp.Contains(name))
  1875. Out('@');
  1876. Out(name);
  1877. return node;
  1878. }
  1879. /// <summary>
  1880. /// Visits the children of the <see cref = "T:System.Linq.Expressions.RuntimeVariablesExpression" />.
  1881. /// </summary>
  1882. /// <param name = "node">The expression to visit.</param>
  1883. /// <returns>
  1884. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1885. /// </returns>
  1886. protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node)
  1887. {
  1888. VisitExpressions('(', node.Variables, ')');
  1889. return node;
  1890. }
  1891. /// <summary>
  1892. /// Visits the children of the <see cref = "T:System.Linq.Expressions.SwitchExpression" />.
  1893. /// </summary>
  1894. /// <param name = "node">The expression to visit.</param>
  1895. /// <returns>
  1896. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1897. /// </returns>
  1898. protected override Expression VisitSwitch(SwitchExpression node)
  1899. {
  1900. Out("switch ");
  1901. Out("(");
  1902. Visit(node.SwitchValue);
  1903. Out(") { ... }");
  1904. return node;
  1905. }
  1906. /// <summary>
  1907. /// Visits the children of the <see cref = "T:System.Linq.Expressions.SwitchCase" />.
  1908. /// </summary>
  1909. /// <param name = "node">The expression to visit.</param>
  1910. /// <returns>
  1911. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1912. /// </returns>
  1913. protected override SwitchCase VisitSwitchCase(SwitchCase node)
  1914. {
  1915. Out("case ");
  1916. VisitExpressions('(', node.TestValues, ')');
  1917. Out(": ...");
  1918. return node;
  1919. }
  1920. /// <summary>
  1921. /// Visits the children of the <see cref = "T:System.Linq.Expressions.TryExpression" />.
  1922. /// </summary>
  1923. /// <param name = "node">The expression to visit.</param>
  1924. /// <returns>
  1925. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1926. /// </returns>
  1927. protected override Expression VisitTry(TryExpression node)
  1928. {
  1929. Out("try { ... }");
  1930. return node;
  1931. }
  1932. /// <summary>
  1933. /// Visits the children of the <see cref = "T:System.Linq.Expressions.TypeBinaryExpression" />.
  1934. /// </summary>
  1935. /// <param name = "node">The expression to visit.</param>
  1936. /// <returns>
  1937. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1938. /// </returns>
  1939. protected override Expression VisitTypeBinary(TypeBinaryExpression node)
  1940. {
  1941. const ExpressionOperatorPrecedence currentPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  1942. string op;
  1943. switch (node.NodeType)
  1944. {
  1945. case ExpressionType.TypeIs:
  1946. op = " is ";
  1947. break;
  1948. case ExpressionType.TypeEqual:
  1949. op = " TypeEqual ";
  1950. break;
  1951. default:
  1952. throw new InvalidOperationException();
  1953. }
  1954. Visit(node.Expression, currentPrecedence);
  1955. Out(op);
  1956. Out(node.TypeOperand.Name);
  1957. return node;
  1958. }
  1959. /// <summary>
  1960. /// Visits the children of the <see cref = "T:System.Linq.Expressions.UnaryExpression" />.
  1961. /// </summary>
  1962. /// <param name = "node">The expression to visit.</param>
  1963. /// <returns>
  1964. /// The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
  1965. /// </returns>
  1966. protected override Expression VisitUnary(UnaryExpression node)
  1967. {
  1968. return VisitUnary(node, _currentPrecedence);
  1969. }
  1970. private Expression VisitUnary(UnaryExpression node, ExpressionOperatorPrecedence outerPrecedence)
  1971. {
  1972. var innerPrecedence = ExpressionOperatorPrecedence.Unary;
  1973. switch (node.NodeType)
  1974. {
  1975. case ExpressionType.TypeAs:
  1976. innerPrecedence = ExpressionOperatorPrecedence.RelationalAndTypeTesting;
  1977. break;
  1978. case ExpressionType.Decrement:
  1979. innerPrecedence = ExpressionOperatorPrecedence.ParenthesisNotNeeded;
  1980. Out("Decrement(");
  1981. break;
  1982. case ExpressionType.Negate:
  1983. case ExpressionType.NegateChecked:
  1984. Out("-");
  1985. break;
  1986. case ExpressionType.UnaryPlus:
  1987. Out("+");
  1988. break;
  1989. case ExpressionType.Not:
  1990. Out("!");
  1991. break;
  1992. case ExpressionType.Quote:
  1993. break;
  1994. case ExpressionType.Increment:
  1995. innerPrecedence = ExpressionOperatorPrecedence.ParenthesisNotNeeded;
  1996. Out("Increment(");
  1997. break;
  1998. case ExpressionType.Throw:
  1999. innerPrecedence = ExpressionOperatorPrecedence.ParenthesisNotNeeded;
  2000. Out("throw ");
  2001. break;
  2002. case ExpressionType.PreIncrementAssign:
  2003. Out("++");
  2004. break;
  2005. case ExpressionType.PreDecrementAssign:
  2006. Out("--");
  2007. break;
  2008. case ExpressionType.OnesComplement:
  2009. Out("~");
  2010. break;
  2011. case ExpressionType.Convert:
  2012. case ExpressionType.ConvertChecked:
  2013. if (node.Method != null && node.Method.Name == "Parse" && node.Method.DeclaringType == typeof(DateTime))
  2014. {
  2015. Out(node.Method.DeclaringType.Name);
  2016. Out(".Parse(");
  2017. }
  2018. else
  2019. {
  2020. Out("(");
  2021. ConvertTypeToCSharpKeywordIncludeNullable(node.Type);
  2022. }
  2023. break;
  2024. case ExpressionType.ArrayLength:
  2025. // we don't want to do nothing for those
  2026. Out("(");
  2027. break;
  2028. default:
  2029. innerPrecedence = ExpressionOperatorPrecedence.ParenthesisNotNeeded;
  2030. Out(node.NodeType.ToString());
  2031. Out("(");
  2032. break;
  2033. }
  2034. SometimesParenthesis(outerPrecedence, innerPrecedence, () => Visit(node.Operand, innerPrecedence));
  2035. switch (node.NodeType)
  2036. {
  2037. case ExpressionType.TypeAs:
  2038. Out(" As ");
  2039. Out(node.Type.Name);
  2040. break;
  2041. case ExpressionType.ArrayLength:
  2042. Out(".Length)");
  2043. break;
  2044. case ExpressionType.Decrement:
  2045. case ExpressionType.Increment:
  2046. Out(")");
  2047. break;
  2048. case ExpressionType.Convert:
  2049. case ExpressionType.ConvertChecked:
  2050. Out(")");
  2051. break;
  2052. case ExpressionType.Negate:
  2053. case ExpressionType.UnaryPlus:
  2054. case ExpressionType.NegateChecked:
  2055. case ExpressionType.Not:
  2056. case ExpressionType.Quote:
  2057. case ExpressionType.Throw:
  2058. case ExpressionType.PreIncrementAssign:
  2059. case ExpressionType.PreDecrementAssign:
  2060. case ExpressionType.OnesComplement:
  2061. break;
  2062. case ExpressionType.PostIncrementAssign:
  2063. Out("++");
  2064. break;
  2065. case ExpressionType.PostDecrementAssign:
  2066. Out("--");
  2067. break;
  2068. default:
  2069. Out(")");
  2070. break;
  2071. }
  2072. return node;
  2073. }
  2074. private static bool ShouldConvert(Type nonNullableType)
  2075. {
  2076. if (nonNullableType.IsEnum())
  2077. return true;
  2078. return nonNullableType.Assembly() == typeof(string).Assembly() && (nonNullableType.IsGenericType() == false);
  2079. }
  2080. }
  2081. }