PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_2_0/Src/Microsoft.Scripting.Core/Ast/BinaryExpression.cs

#
C# | 1037 lines | 844 code | 86 blank | 107 comment | 257 complexity | 3824fb8da75fb591a3969955b921e3a9 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0

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

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System; using Microsoft;
  16. using System.Diagnostics;
  17. using System.Reflection;
  18. using Microsoft.Scripting.Utils;
  19. using System.Text;
  20. namespace Microsoft.Linq.Expressions {
  21. //CONFORMING
  22. public sealed class BinaryExpression : Expression {
  23. private readonly Expression _left;
  24. private readonly Expression _right;
  25. private readonly MethodInfo _method;
  26. private readonly LambdaExpression _conversion;
  27. internal BinaryExpression(Annotations annotations, ExpressionType nodeType, Expression left, Expression right, Type type)
  28. : this(annotations, nodeType, left, right, type, null, null) {
  29. }
  30. internal BinaryExpression(Annotations annotations, ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method)
  31. : this(annotations, nodeType, left, right, type, method, null) {
  32. }
  33. internal BinaryExpression(Annotations annotations,
  34. ExpressionType nodeType,
  35. Expression left,
  36. Expression right,
  37. Type type,
  38. MethodInfo method,
  39. LambdaExpression conversion)
  40. : base(nodeType, type, false, annotations, true, nodeType == ExpressionType.ArrayIndex) {
  41. // Only Coalesce can have a conversion
  42. Debug.Assert(conversion == null || nodeType == ExpressionType.Coalesce);
  43. _left = left;
  44. _right = right;
  45. _method = method;
  46. _conversion = conversion;
  47. }
  48. public Expression Right {
  49. get { return _right; }
  50. }
  51. public Expression Left {
  52. get { return _left; }
  53. }
  54. public MethodInfo Method {
  55. get { return _method; }
  56. }
  57. public LambdaExpression Conversion {
  58. get { return _conversion; }
  59. }
  60. public bool IsLifted {
  61. get {
  62. if (this.NodeType == ExpressionType.Coalesce) {
  63. return false;
  64. }
  65. bool leftIsNullable = TypeUtils.IsNullableType(_left.Type);
  66. if (_method != null) {
  67. return leftIsNullable && _method.GetParametersCached()[0].ParameterType != _left.Type;
  68. }
  69. return leftIsNullable;
  70. }
  71. }
  72. public bool IsLiftedToNull {
  73. get {
  74. return this.IsLifted && TypeUtils.IsNullableType(this.Type);
  75. }
  76. }
  77. internal override void BuildString(StringBuilder builder) {
  78. ContractUtils.RequiresNotNull(builder, "builder");
  79. switch (NodeType) {
  80. case ExpressionType.ArrayIndex:
  81. _left.BuildString(builder);
  82. builder.Append("[");
  83. _right.BuildString(builder);
  84. builder.Append("]");
  85. break;
  86. default:
  87. string op = GetOperator();
  88. if (op != null) {
  89. builder.Append("(");
  90. _left.BuildString(builder);
  91. builder.Append(" ");
  92. builder.Append(op);
  93. builder.Append(" ");
  94. _right.BuildString(builder);
  95. builder.Append(")");
  96. } else {
  97. builder.Append(NodeType);
  98. builder.Append("(");
  99. _left.BuildString(builder);
  100. builder.Append(", ");
  101. _right.BuildString(builder);
  102. builder.Append(")");
  103. }
  104. break;
  105. }
  106. }
  107. internal override Expression Accept(ExpressionTreeVisitor visitor) {
  108. return visitor.VisitBinary(this);
  109. }
  110. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  111. private string GetOperator() {
  112. switch (this.NodeType) {
  113. case ExpressionType.Add:
  114. case ExpressionType.AddChecked:
  115. return "+";
  116. case ExpressionType.Subtract:
  117. case ExpressionType.SubtractChecked:
  118. return "-";
  119. case ExpressionType.Multiply:
  120. case ExpressionType.MultiplyChecked:
  121. return "*";
  122. case ExpressionType.Divide:
  123. return "/";
  124. case ExpressionType.Modulo:
  125. return "%";
  126. case ExpressionType.Power:
  127. return "^";
  128. case ExpressionType.And:
  129. if (this.Type == typeof(bool) || this.Type == typeof(bool?)) {
  130. return "And";
  131. }
  132. return "&";
  133. case ExpressionType.AndAlso:
  134. return "&&";
  135. case ExpressionType.Or:
  136. if (this.Type == typeof(bool) || this.Type == typeof(bool?)) {
  137. return "Or";
  138. }
  139. return "|";
  140. case ExpressionType.OrElse:
  141. return "||";
  142. case ExpressionType.LessThan:
  143. return "<";
  144. case ExpressionType.LessThanOrEqual:
  145. return "<=";
  146. case ExpressionType.GreaterThan:
  147. return ">";
  148. case ExpressionType.GreaterThanOrEqual:
  149. return ">=";
  150. case ExpressionType.Equal:
  151. return "=";
  152. case ExpressionType.NotEqual:
  153. return "!=";
  154. case ExpressionType.Coalesce:
  155. return "??";
  156. case ExpressionType.RightShift:
  157. return ">>";
  158. case ExpressionType.LeftShift:
  159. return "<<";
  160. case ExpressionType.ExclusiveOr:
  161. return "^";
  162. }
  163. return null;
  164. }
  165. }
  166. public partial class Expression {
  167. //CONFORMING
  168. private static BinaryExpression GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull, Annotations annotations) {
  169. // try exact match first
  170. MethodInfo method = GetUserDefinedBinaryOperator(binaryType, left.Type, right.Type, name);
  171. if (method != null) {
  172. return new BinaryExpression(annotations, binaryType, left, right, method.ReturnType, method);
  173. }
  174. // try lifted call
  175. if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type)) {
  176. Type nnLeftType = TypeUtils.GetNonNullableType(left.Type);
  177. Type nnRightType = TypeUtils.GetNonNullableType(right.Type);
  178. method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
  179. if (method != null && method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
  180. if (method.ReturnType != typeof(bool) || liftToNull) {
  181. return new BinaryExpression(annotations, binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
  182. } else {
  183. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool), method);
  184. }
  185. }
  186. }
  187. return null;
  188. }
  189. //CONFORMING
  190. private static BinaryExpression GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull, Annotations annotations) {
  191. System.Diagnostics.Debug.Assert(method != null);
  192. ValidateOperator(method);
  193. ParameterInfo[] pms = method.GetParametersCached();
  194. if (pms.Length != 2)
  195. throw Error.IncorrectNumberOfMethodCallArguments(method);
  196. if (ParameterIsAssignable(pms[0], left.Type) && ParameterIsAssignable(pms[1], right.Type)) {
  197. ValidateParamswithOperandsOrThrow(pms[0].ParameterType, left.Type, binaryType, method.Name);
  198. ValidateParamswithOperandsOrThrow(pms[1].ParameterType, right.Type, binaryType, method.Name);
  199. return new BinaryExpression(annotations, binaryType, left, right, method.ReturnType, method);
  200. }
  201. // check for lifted call
  202. if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type) &&
  203. ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
  204. ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right.Type)) &&
  205. method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
  206. if (method.ReturnType != typeof(bool) || liftToNull) {
  207. return new BinaryExpression(annotations, binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
  208. } else {
  209. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool), method);
  210. }
  211. }
  212. throw Error.OperandTypesDoNotMatchParameters(binaryType, method.Name);
  213. }
  214. //CONFORMING
  215. private static BinaryExpression GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull, Annotations annotations) {
  216. BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, name, left, right, liftToNull, annotations);
  217. if (b != null) {
  218. ParameterInfo[] pis = b.Method.GetParametersCached();
  219. ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, binaryType, name);
  220. ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, binaryType, name);
  221. return b;
  222. }
  223. throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
  224. }
  225. //CONFORMING
  226. private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) {
  227. // UNDONE: This algorithm is wrong, we should be checking for uniqueness and erroring if
  228. // UNDONE: it is defined on both types.
  229. Type[] types = new Type[] { leftType, rightType };
  230. Type nnLeftType = TypeUtils.GetNonNullableType(leftType);
  231. Type nnRightType = TypeUtils.GetNonNullableType(rightType);
  232. BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
  233. MethodInfo method = nnLeftType.GetMethod(name, flags, null, types, null);
  234. if (method == null && leftType != rightType) {
  235. method = nnRightType.GetMethod(name, flags, null, types, null);
  236. }
  237. if (IsLiftingConditionalLogicalOperator(leftType, rightType, method, binaryType)) {
  238. method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
  239. }
  240. return method;
  241. }
  242. //CONFORMING
  243. private static bool IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType) {
  244. return TypeUtils.IsNullableType(right) &&
  245. TypeUtils.IsNullableType(left) &&
  246. method == null &&
  247. (binaryType == ExpressionType.AndAlso || binaryType == ExpressionType.OrElse);
  248. }
  249. //CONFORMING
  250. private static bool ParameterIsAssignable(ParameterInfo pi, Type argType) {
  251. Type pType = pi.ParameterType;
  252. if (pType.IsByRef)
  253. pType = pType.GetElementType();
  254. return TypeUtils.AreReferenceAssignable(pType, argType);
  255. }
  256. //CONFORMING
  257. private static void ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name) {
  258. if (TypeUtils.IsNullableType(paramType) && !TypeUtils.IsNullableType(operandType)) {
  259. throw Error.OperandTypesDoNotMatchParameters(exprType, name);
  260. }
  261. }
  262. //CONFORMING
  263. private static void ValidateOperator(MethodInfo method) {
  264. System.Diagnostics.Debug.Assert(method != null);
  265. ValidateMethodInfo(method);
  266. if (!method.IsStatic)
  267. throw Error.UserDefinedOperatorMustBeStatic(method);
  268. if (method.ReturnType == typeof(void))
  269. throw Error.UserDefinedOperatorMustNotBeVoid(method);
  270. }
  271. //TODO: consider moving to utils. It is used in many places.
  272. //CONFORMING
  273. private static void ValidateMethodInfo(MethodInfo method) {
  274. if (method.IsGenericMethodDefinition)
  275. throw Error.MethodIsGeneric(method);
  276. if (method.ContainsGenericParameters)
  277. throw Error.MethodContainsGenericParameters(method);
  278. }
  279. //CONFORMING
  280. private static bool IsNullComparison(Expression left, Expression right) {
  281. // If we have x==null, x!=null, null==x or null!=x where x is
  282. // nullable but not null, then this is treated as a call to x.HasValue
  283. // and is legal even if there is no equality operator defined on the
  284. // type of x.
  285. if (IsNullConstant(left) && !IsNullConstant(right) && TypeUtils.IsNullableType(right.Type)) {
  286. return true;
  287. }
  288. if (IsNullConstant(right) && !IsNullConstant(left) && TypeUtils.IsNullableType(left.Type)) {
  289. return true;
  290. }
  291. return false;
  292. }
  293. //CONFORMING
  294. // Note: this has different meaning than ConstantCheck.IsNull
  295. // That function attempts to determine if the result of a tree will be
  296. // null at runtime. This function is used at tree construction time and
  297. // only looks for a ConstantExpression with a null Value. It can't
  298. // become "smarter" or that would break tree construction.
  299. private static bool IsNullConstant(Expression e) {
  300. var c = e as ConstantExpression;
  301. return c != null && c.Value == null;
  302. }
  303. //CONFORMING
  304. private static void ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method) {
  305. ValidateOperator(method);
  306. ParameterInfo[] pms = method.GetParametersCached();
  307. if (pms.Length != 2)
  308. throw Error.IncorrectNumberOfMethodCallArguments(method);
  309. if (!ParameterIsAssignable(pms[0], left)) {
  310. if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left))))
  311. throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
  312. }
  313. if (!ParameterIsAssignable(pms[1], right)) {
  314. if (!(TypeUtils.IsNullableType(right) && ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right))))
  315. throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
  316. }
  317. if (pms[0].ParameterType != pms[1].ParameterType)
  318. throw Error.LogicalOperatorMustHaveConsistentTypes(nodeType, method.Name);
  319. if (method.ReturnType != pms[0].ParameterType)
  320. throw Error.LogicalOperatorMustHaveConsistentTypes(nodeType, method.Name);
  321. if (IsValidLiftedConditionalLogicalOperator(left, right, pms)) {
  322. left = TypeUtils.GetNonNullableType(left);
  323. right = TypeUtils.GetNonNullableType(left);
  324. }
  325. MethodInfo opTrue = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_True");
  326. MethodInfo opFalse = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_False");
  327. if (opTrue == null || opTrue.ReturnType != typeof(bool) ||
  328. opFalse == null || opFalse.ReturnType != typeof(bool)) {
  329. throw Error.LogicalOperatorMustHaveBooleanOperators(nodeType, method.Name);
  330. }
  331. }
  332. //CONFORMING
  333. private static bool IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms) {
  334. return left == right && TypeUtils.IsNullableType(right) && pms[1].ParameterType == TypeUtils.GetNonNullableType(right);
  335. }
  336. //CONFORMING
  337. public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right) {
  338. return MakeBinary(binaryType, left, right, false, null, null);
  339. }
  340. //CONFORMING
  341. public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method) {
  342. return MakeBinary(binaryType, left, right, liftToNull, method, null, null);
  343. }
  344. //CONFORMING
  345. public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion) {
  346. return MakeBinary(binaryType, left, right, liftToNull, method, conversion, null);
  347. }
  348. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  349. public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion, Annotations annotations) {
  350. switch (binaryType) {
  351. case ExpressionType.Add:
  352. return Expression.Add(left, right, method, annotations);
  353. case ExpressionType.AddChecked:
  354. return Expression.AddChecked(left, right, method, annotations);
  355. case ExpressionType.Subtract:
  356. return Expression.Subtract(left, right, method, annotations);
  357. case ExpressionType.SubtractChecked:
  358. return Expression.SubtractChecked(left, right, method, annotations);
  359. case ExpressionType.Multiply:
  360. return Expression.Multiply(left, right, method, annotations);
  361. case ExpressionType.MultiplyChecked:
  362. return Expression.MultiplyChecked(left, right, method, annotations);
  363. case ExpressionType.Divide:
  364. return Expression.Divide(left, right, method, annotations);
  365. case ExpressionType.Modulo:
  366. return Expression.Modulo(left, right, method, annotations);
  367. case ExpressionType.Power:
  368. return Expression.Power(left, right, method, annotations);
  369. case ExpressionType.And:
  370. return Expression.And(left, right, method, annotations);
  371. case ExpressionType.AndAlso:
  372. return Expression.AndAlso(left, right, method, annotations);
  373. case ExpressionType.Or:
  374. return Expression.Or(left, right, method, annotations);
  375. case ExpressionType.OrElse:
  376. return Expression.OrElse(left, right, method, annotations);
  377. case ExpressionType.LessThan:
  378. return Expression.LessThan(left, right, liftToNull, method, annotations);
  379. case ExpressionType.LessThanOrEqual:
  380. return Expression.LessThanOrEqual(left, right, liftToNull, method, annotations);
  381. case ExpressionType.GreaterThan:
  382. return Expression.GreaterThan(left, right, liftToNull, method, annotations);
  383. case ExpressionType.GreaterThanOrEqual:
  384. return Expression.GreaterThanOrEqual(left, right, liftToNull, method, annotations);
  385. case ExpressionType.Equal:
  386. return Expression.Equal(left, right, liftToNull, method, annotations);
  387. case ExpressionType.NotEqual:
  388. return Expression.NotEqual(left, right, liftToNull, method, annotations);
  389. case ExpressionType.ExclusiveOr:
  390. return Expression.ExclusiveOr(left, right, method, annotations);
  391. case ExpressionType.Coalesce:
  392. return Expression.Coalesce(left, right, conversion, annotations);
  393. case ExpressionType.ArrayIndex:
  394. return Expression.ArrayIndex(left, right);
  395. case ExpressionType.RightShift:
  396. return Expression.RightShift(left, right, method, annotations);
  397. case ExpressionType.LeftShift:
  398. return Expression.LeftShift(left, right, method, annotations);
  399. default:
  400. throw Error.UnhandledBinary(binaryType);
  401. }
  402. }
  403. #region Equality Operators
  404. //CONFORMING
  405. public static BinaryExpression Equal(Expression left, Expression right) {
  406. return Equal(left, right, false, null, null);
  407. }
  408. public static BinaryExpression Equal(Expression left, Expression right, Annotations annotations) {
  409. return Equal(left, right, false, null, annotations);
  410. }
  411. public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  412. return Equal(left, right, liftToNull, method, null);
  413. }
  414. //CONFORMING
  415. public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  416. RequiresCanRead(left, "left");
  417. RequiresCanRead(right, "right");
  418. if (method == null) {
  419. return GetEqualityComparisonOperator(ExpressionType.Equal, "op_Equality", left, right, liftToNull, annotations);
  420. }
  421. return GetMethodBasedBinaryOperator(ExpressionType.Equal, left, right, method, liftToNull, annotations);
  422. }
  423. public static BinaryExpression NotEqual(Expression left, Expression right) {
  424. return NotEqual(left, right, null);
  425. }
  426. //CONFORMING
  427. public static BinaryExpression NotEqual(Expression left, Expression right, Annotations annotations) {
  428. return NotEqual(left, right, false, null, annotations);
  429. }
  430. public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  431. return NotEqual(left, right, liftToNull, method, null);
  432. }
  433. //CONFORMING
  434. public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  435. RequiresCanRead(left, "left");
  436. RequiresCanRead(right, "right");
  437. if (method == null) {
  438. return GetEqualityComparisonOperator(ExpressionType.NotEqual, "op_Inequality", left, right, liftToNull, annotations);
  439. }
  440. return GetMethodBasedBinaryOperator(ExpressionType.NotEqual, left, right, method, liftToNull, annotations);
  441. }
  442. //CONFORMING
  443. private static BinaryExpression GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull, Annotations annotations) {
  444. // known comparison - numeric types, bools, object, enums
  445. if (left.Type == right.Type && (TypeUtils.IsNumeric(left.Type) ||
  446. left.Type == typeof(object) ||
  447. TypeUtils.IsBool(left.Type) ||
  448. TypeUtils.GetNonNullableType(left.Type).IsEnum)) {
  449. if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
  450. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
  451. } else {
  452. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
  453. }
  454. }
  455. // look for user defined operator
  456. BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, opName, left, right, liftToNull, annotations);
  457. if (b != null) {
  458. return b;
  459. }
  460. if (TypeUtils.HasBuiltInEqualityOperator(left.Type, right.Type) || IsNullComparison(left, right)) {
  461. if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
  462. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
  463. } else {
  464. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
  465. }
  466. }
  467. throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
  468. }
  469. #endregion
  470. #region Comparison Expressions
  471. //CONFORMING
  472. public static BinaryExpression GreaterThan(Expression left, Expression right) {
  473. return GreaterThan(left, right, false, null);
  474. }
  475. public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  476. return GreaterThan(left, right, liftToNull, method, null);
  477. }
  478. //CONFORMING
  479. public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  480. RequiresCanRead(left, "left");
  481. RequiresCanRead(right, "right");
  482. if (method == null) {
  483. return GetComparisonOperator(ExpressionType.GreaterThan, "op_GreaterThan", left, right, liftToNull, annotations);
  484. }
  485. return GetMethodBasedBinaryOperator(ExpressionType.GreaterThan, left, right, method, liftToNull, annotations);
  486. }
  487. //CONFORMING
  488. public static BinaryExpression LessThan(Expression left, Expression right) {
  489. return LessThan(left, right, false, null);
  490. }
  491. public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  492. return LessThan(left, right, liftToNull, method, null);
  493. }
  494. //CONFORMING
  495. public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  496. RequiresCanRead(left, "left");
  497. RequiresCanRead(right, "right");
  498. if (method == null) {
  499. return GetComparisonOperator(ExpressionType.LessThan, "op_LessThan", left, right, liftToNull, annotations);
  500. }
  501. return GetMethodBasedBinaryOperator(ExpressionType.LessThan, left, right, method, liftToNull, annotations);
  502. }
  503. //CONFORMING
  504. public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) {
  505. return GreaterThanOrEqual(left, right, false, null);
  506. }
  507. public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  508. return GreaterThanOrEqual(left, right, liftToNull, method, null);
  509. }
  510. //CONFORMING
  511. public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  512. RequiresCanRead(left, "left");
  513. RequiresCanRead(right, "right");
  514. if (method == null) {
  515. return GetComparisonOperator(ExpressionType.GreaterThanOrEqual, "op_GreaterThanOrEqual", left, right, liftToNull, annotations);
  516. }
  517. return GetMethodBasedBinaryOperator(ExpressionType.GreaterThanOrEqual, left, right, method, liftToNull, annotations);
  518. }
  519. //CONFORMING
  520. public static BinaryExpression LessThanOrEqual(Expression left, Expression right) {
  521. return LessThanOrEqual(left, right, false, null);
  522. }
  523. public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
  524. return LessThanOrEqual(left, right, liftToNull, method, null);
  525. }
  526. //CONFORMING
  527. public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
  528. RequiresCanRead(left, "left");
  529. RequiresCanRead(right, "right");
  530. if (method == null) {
  531. return GetComparisonOperator(ExpressionType.LessThanOrEqual, "op_LessThanOrEqual", left, right, liftToNull, annotations);
  532. }
  533. return GetMethodBasedBinaryOperator(ExpressionType.LessThanOrEqual, left, right, method, liftToNull, annotations);
  534. }
  535. //CONFORMING
  536. private static BinaryExpression GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull, Annotations annotations) {
  537. if (left.Type == right.Type && TypeUtils.IsNumeric(left.Type)) {
  538. if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
  539. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
  540. } else {
  541. return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
  542. }
  543. }
  544. return GetUserDefinedBinaryOperatorOrThrow(binaryType, opName, left, right, liftToNull, annotations);
  545. }
  546. #endregion
  547. #region Boolean Expressions
  548. //CONFORMING
  549. public static BinaryExpression AndAlso(Expression left, Expression right) {
  550. return AndAlso(left, right, null, null);
  551. }
  552. //CONFORMING
  553. public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) {
  554. return AndAlso(left, right, method, null);
  555. }
  556. public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  557. RequiresCanRead(left, "left");
  558. RequiresCanRead(right, "right");
  559. Type returnType;
  560. if (method == null) {
  561. if (left.Type == right.Type && TypeUtils.IsBool(left.Type)) {
  562. return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, left.Type);
  563. }
  564. method = GetUserDefinedBinaryOperator(ExpressionType.AndAlso, left.Type, right.Type, "op_BitwiseAnd");
  565. if (method != null) {
  566. ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
  567. returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
  568. return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, returnType, method);
  569. }
  570. throw Error.BinaryOperatorNotDefined(ExpressionType.AndAlso, left.Type, right.Type);
  571. }
  572. ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
  573. returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
  574. return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, returnType, method);
  575. }
  576. //CONFORMING
  577. public static BinaryExpression OrElse(Expression left, Expression right) {
  578. return OrElse(left, right, null, null);
  579. }
  580. //CONFORMING
  581. public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) {
  582. return OrElse(left, right, method, null);
  583. }
  584. public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  585. RequiresCanRead(left, "left");
  586. RequiresCanRead(right, "right");
  587. Type returnType;
  588. if (method == null) {
  589. if (left.Type == right.Type && TypeUtils.IsBool(left.Type)) {
  590. return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, left.Type);
  591. }
  592. method = GetUserDefinedBinaryOperator(ExpressionType.OrElse, left.Type, right.Type, "op_BitwiseOr");
  593. if (method != null) {
  594. ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
  595. returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
  596. return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, returnType, method);
  597. }
  598. throw Error.BinaryOperatorNotDefined(ExpressionType.OrElse, left.Type, right.Type);
  599. }
  600. ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
  601. returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
  602. return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, returnType, method);
  603. }
  604. #endregion
  605. #region Coalescing Expressions
  606. //CONFORMING
  607. public static BinaryExpression Coalesce(Expression left, Expression right) {
  608. return Coalesce(left, right, null, null);
  609. }
  610. //CONFORMING
  611. public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) {
  612. return Coalesce(left, right, conversion, null);
  613. }
  614. public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion, Annotations annotations) {
  615. RequiresCanRead(left, "left");
  616. RequiresCanRead(right, "right");
  617. if (conversion == null) {
  618. Type resultType = ValidateCoalesceArgTypes(left.Type, right.Type);
  619. return new BinaryExpression(annotations, ExpressionType.Coalesce, left, right, resultType);
  620. }
  621. if (left.Type.IsValueType && !TypeUtils.IsNullableType(left.Type)) {
  622. throw Error.CoalesceUsedOnNonNullType();
  623. }
  624. Type delegateType = conversion.Type;
  625. Debug.Assert(TypeUtils.AreAssignable(typeof(System.Delegate), delegateType) && delegateType != typeof(System.Delegate));
  626. MethodInfo method = delegateType.GetMethod("Invoke");
  627. if (method.ReturnType == typeof(void))
  628. throw Error.UserDefinedOperatorMustNotBeVoid(conversion);
  629. ParameterInfo[] pms = method.GetParametersCached();
  630. Debug.Assert(pms.Length == conversion.Parameters.Count);
  631. if (pms.Length != 1)
  632. throw Error.IncorrectNumberOfMethodCallArguments(conversion);
  633. // The return type must match exactly.
  634. // CONSIDER: We could weaken this restriction and
  635. // CONSIDER: say that the return type must be assignable to from
  636. // CONSIDER: the return type of the lambda.
  637. if (method.ReturnType != right.Type) {
  638. throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
  639. }
  640. // The parameter of the conversion lambda must either be assignable
  641. // from the erased or unerased type of the left hand side.
  642. if (!ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
  643. !ParameterIsAssignable(pms[0], left.Type)) {
  644. throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
  645. }
  646. return new BinaryExpression(annotations, ExpressionType.Coalesce, left, right, right.Type, null, conversion);
  647. }
  648. //CONFORMING
  649. private static Type ValidateCoalesceArgTypes(Type left, Type right) {
  650. Type leftStripped = TypeUtils.GetNonNullableType(left);
  651. if (left.IsValueType && !TypeUtils.IsNullableType(left)) {
  652. throw Error.CoalesceUsedOnNonNullType();
  653. } else if (TypeUtils.IsNullableType(left) && TypeUtils.IsImplicitlyConvertible(right, leftStripped)) {
  654. return leftStripped;
  655. } else if (TypeUtils.IsImplicitlyConvertible(right, left)) {
  656. return left;
  657. } else if (TypeUtils.IsImplicitlyConvertible(leftStripped, right)) {
  658. return right;
  659. } else {
  660. throw Error.ArgumentTypesMustMatch();
  661. }
  662. }
  663. #endregion
  664. #region Arithmetic Expressions
  665. //CONFORMING
  666. public static BinaryExpression Add(Expression left, Expression right) {
  667. return Add(left, right, null, null);
  668. }
  669. //CONFORMING
  670. public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) {
  671. return Add(left, right, method, null);
  672. }
  673. public static BinaryExpression Add(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  674. RequiresCanRead(left, "left");
  675. RequiresCanRead(right, "right");
  676. if (method == null) {
  677. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  678. return new BinaryExpression(annotations, ExpressionType.Add, left, right, left.Type);
  679. }
  680. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true, annotations);
  681. }
  682. return GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true, annotations);
  683. }
  684. //CONFORMING
  685. public static BinaryExpression AddChecked(Expression left, Expression right) {
  686. return AddChecked(left, right, null, null);
  687. }
  688. //CONFORMING
  689. public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) {
  690. return AddChecked(left, right, method, null);
  691. }
  692. public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  693. RequiresCanRead(left, "left");
  694. RequiresCanRead(right, "right");
  695. if (method == null) {
  696. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  697. return new BinaryExpression(annotations, ExpressionType.AddChecked, left, right, left.Type);
  698. }
  699. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.AddChecked, "op_Addition", left, right, false, annotations);
  700. }
  701. return GetMethodBasedBinaryOperator(ExpressionType.AddChecked, left, right, method, true, annotations);
  702. }
  703. //CONFORMING
  704. public static BinaryExpression Subtract(Expression left, Expression right) {
  705. return Subtract(left, right, null, null);
  706. }
  707. //CONFORMING
  708. public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) {
  709. return Subtract(left, right, method, null);
  710. }
  711. public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  712. RequiresCanRead(left, "left");
  713. RequiresCanRead(right, "right");
  714. if (method == null) {
  715. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  716. return new BinaryExpression(annotations, ExpressionType.Subtract, left, right, left.Type);
  717. }
  718. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Subtract, "op_Subtraction", left, right, true, annotations);
  719. }
  720. return GetMethodBasedBinaryOperator(ExpressionType.Subtract, left, right, method, true, annotations);
  721. }
  722. //CONFORMING
  723. public static BinaryExpression SubtractChecked(Expression left, Expression right) {
  724. return SubtractChecked(left, right, null, null);
  725. }
  726. //CONFORMING
  727. public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) {
  728. return SubtractChecked(left, right, method, null);
  729. }
  730. public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  731. RequiresCanRead(left, "left");
  732. RequiresCanRead(right, "right");
  733. if (method == null) {
  734. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  735. return new BinaryExpression(annotations, ExpressionType.SubtractChecked, left, right, left.Type);
  736. }
  737. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.SubtractChecked, "op_Subtraction", left, right, true, annotations);
  738. }
  739. return GetMethodBasedBinaryOperator(ExpressionType.SubtractChecked, left, right, method, true, annotations);
  740. }
  741. //CONFORMING
  742. public static BinaryExpression Divide(Expression left, Expression right) {
  743. return Divide(left, right, null, null);
  744. }
  745. //CONFORMING
  746. public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) {
  747. return Divide(left, right, method, null);
  748. }
  749. public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  750. RequiresCanRead(left, "left");
  751. RequiresCanRead(right, "right");
  752. if (method == null) {
  753. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  754. return new BinaryExpression(annotations, ExpressionType.Divide, left, right, left.Type);
  755. }
  756. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Divide, "op_Division", left, right, true, annotations);
  757. }
  758. return GetMethodBasedBinaryOperator(ExpressionType.Divide, left, right, method, true, annotations);
  759. }
  760. //CONFORMING
  761. public static BinaryExpression Modulo(Expression left, Expression right) {
  762. return Modulo(left, right, null, null);
  763. }
  764. //CONFORMING
  765. public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method) {
  766. return Modulo(left, right, method, null);
  767. }
  768. public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  769. RequiresCanRead(left, "left");
  770. RequiresCanRead(right, "right");
  771. if (method == null) {
  772. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  773. return new BinaryExpression(annotations, ExpressionType.Modulo, left, right, left.Type);
  774. }
  775. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Modulo, "op_Modulus", left, right, true, annotations);
  776. }
  777. return GetMethodBasedBinaryOperator(ExpressionType.Modulo, left, right, method, true, annotations);
  778. }
  779. //CONFORMING
  780. public static BinaryExpression Multiply(Expression left, Expression right) {
  781. return Multiply(left, right, null, null);
  782. }
  783. //CONFORMING
  784. public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) {
  785. return Multiply(left, right, method, null);
  786. }
  787. public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  788. RequiresCanRead(left, "left");
  789. RequiresCanRead(right, "right");
  790. if (method == null) {
  791. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  792. return new BinaryExpression(annotations, ExpressionType.Multiply, left, right, left.Type);
  793. }
  794. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Multiply, "op_Multiply", left, right, true, annotations);
  795. }
  796. return GetMethodBasedBinaryOperator(ExpressionType.Multiply, left, right, method, true, annotations);
  797. }
  798. //CONFORMING
  799. public static BinaryExpression MultiplyChecked(Expression left, Expression right) {
  800. return MultiplyChecked(left, right, null, null);
  801. }
  802. //CONFORMING
  803. public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) {
  804. return MultiplyChecked(left, right, method, null);
  805. }
  806. public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  807. RequiresCanRead(left, "left");
  808. RequiresCanRead(right, "right");
  809. if (method == null) {
  810. if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
  811. return new BinaryExpression(annotations, ExpressionType.MultiplyChecked, left, right, left.Type);
  812. }
  813. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.MultiplyChecked, "op_Multiply", left, right, true, annotations);
  814. }
  815. return GetMethodBasedBinaryOperator(ExpressionType.MultiplyChecked, left, right, method, true, annotations);
  816. }
  817. //CONFORMING
  818. public static BinaryExpression LeftShift(Expression left, Expression right) {
  819. return LeftShift(left, right, null, null);
  820. }
  821. //CONFORMING
  822. public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) {
  823. return LeftShift(left, right, method, null);
  824. }
  825. public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  826. RequiresCanRead(left, "left");
  827. RequiresCanRead(right, "right");
  828. if (method == null) {
  829. if (TypeUtils.IsInteger(left.Type) && TypeUtils.GetNonNullableType(right.Type) == typeof(int)) {
  830. return new BinaryExpression(annotations, ExpressionType.LeftShift, left, right, left.Type);
  831. }
  832. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.LeftShift, "op_LeftShift", left, right, true, annotations);
  833. }
  834. return GetMethodBasedBinaryOperator(ExpressionType.LeftShift, left, right, method, true, annotations);
  835. }
  836. //CONFORMING
  837. public static BinaryExpression RightShift(Expression left, Expression right) {
  838. return RightShift(left, right, null, null);
  839. }
  840. //CONFORMING
  841. public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) {
  842. return RightShift(left, right, method, null);
  843. }
  844. public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method, Annotations annotations) {
  845. RequiresCanRead(left, "left");
  846. RequiresCanRead(right, "right");
  847. if (method == null) {
  848. if (TypeUtils.IsInteger(left.Type) && TypeUtils.GetNonNullableType(right.Type) == typeof(int)) {
  849. return new BinaryExpression(annotations, ExpressionType.RightShift, left, right, left.Type);
  850. }
  851. return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.RightShift, "op_RightShift", left, right, true, annotations);
  852. }
  853. return GetMethodBasedBinaryOperator(ExpressionType.RightShift, left, right, method, true, annotations);
  854. }
  855. //CONFORMING
  856. public static BinaryExpression And(Expression left, Expression right) {

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