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

/IronPython_2_0/Src/Microsoft.Scripting.Core/Actions/Restrictions.cs

#
C# | 261 lines | 196 code | 40 blank | 25 comment | 39 complexity | f53dff18d071d7d196f36da52a22e6bc 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
  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.Collections.Generic;
  17. using Microsoft.Linq.Expressions;
  18. using Microsoft.Scripting.Utils;
  19. namespace Microsoft.Scripting.Actions {
  20. public sealed class Restrictions {
  21. private class Restriction {
  22. internal enum RestrictionKind {
  23. Type,
  24. Instance,
  25. Custom
  26. };
  27. private readonly RestrictionKind _kind;
  28. // Simplification ... for now just one kind of restriction rather than hierarchy.
  29. private readonly Expression _expression;
  30. private readonly Type _type;
  31. private readonly object _instance; // TODO: WeakRef ???
  32. internal RestrictionKind Kind {
  33. get { return _kind; }
  34. }
  35. internal Expression Expression {
  36. get { return _expression; }
  37. }
  38. internal Type Type {
  39. get { return _type; }
  40. }
  41. internal object Instance {
  42. get { return _instance; }
  43. }
  44. internal Restriction(Expression parameter, Type type) {
  45. _kind = RestrictionKind.Type;
  46. _expression = parameter;
  47. _type = type;
  48. }
  49. internal Restriction(Expression parameter, object instance) {
  50. _kind = RestrictionKind.Instance;
  51. _expression = parameter;
  52. _instance = instance;
  53. }
  54. internal Restriction(Expression expression) {
  55. _kind = RestrictionKind.Custom;
  56. _expression = expression;
  57. }
  58. public override bool Equals(object obj) {
  59. Restriction other = obj as Restriction;
  60. if (other == null) {
  61. return false;
  62. }
  63. if (other.Kind != Kind ||
  64. other.Expression != Expression) {
  65. return false;
  66. }
  67. switch (other.Kind) {
  68. case RestrictionKind.Instance:
  69. return other.Instance == Instance;
  70. case RestrictionKind.Type:
  71. return other.Type == Type;
  72. default:
  73. return false;
  74. }
  75. }
  76. public override int GetHashCode() {
  77. // lots of collisions but we don't hash Restrictions ever
  78. return (int)Kind ^ Expression.GetHashCode();
  79. }
  80. }
  81. private readonly Restriction[] _restrictions;
  82. private Restrictions(params Restriction[] restrictions) {
  83. _restrictions = restrictions;
  84. }
  85. private bool IsEmpty {
  86. get {
  87. return _restrictions.Length == 0;
  88. }
  89. }
  90. public Restrictions Merge(Restrictions restrictions) {
  91. if (restrictions.IsEmpty) {
  92. return this;
  93. } else if (IsEmpty) {
  94. return restrictions;
  95. } else {
  96. List<Restriction> res = new List<Restriction>(_restrictions.Length + restrictions._restrictions.Length);
  97. AddRestrictions(_restrictions, res);
  98. AddRestrictions(restrictions._restrictions, res);
  99. return new Restrictions(res.ToArray());
  100. }
  101. }
  102. /// <summary>
  103. /// Adds unique restrictions and doesn't add restrictions which are alerady present
  104. /// </summary>
  105. private static void AddRestrictions(Restriction[] list, List<Restriction> res) {
  106. foreach (Restriction r in list) {
  107. bool found = false;
  108. for (int j = 0; j < res.Count; j++) {
  109. if (res[j] == r) {
  110. found = true;
  111. }
  112. }
  113. if (!found) {
  114. res.Add(r);
  115. }
  116. }
  117. }
  118. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  119. public static readonly Restrictions Empty = new Restrictions();
  120. public static Restrictions TypeRestriction(Expression expression, Type type) {
  121. ContractUtils.RequiresNotNull(expression, "expression");
  122. ContractUtils.RequiresNotNull(type, "type");
  123. if (expression.Type == type && type.IsSealedOrValueType()) {
  124. return Restrictions.Empty;
  125. }
  126. return new Restrictions(new Restriction(expression, type));
  127. }
  128. public static Restrictions InstanceRestriction(Expression expression, object instance) {
  129. ContractUtils.RequiresNotNull(expression, "expression");
  130. return new Restrictions(new Restriction(expression, instance));
  131. }
  132. public static Restrictions ExpressionRestriction(Expression expression) {
  133. ContractUtils.RequiresNotNull(expression, "expression");
  134. ContractUtils.Requires(expression.Type == typeof(bool), "expression");
  135. return new Restrictions(new Restriction(expression));
  136. }
  137. public static Restrictions Combine(IList<MetaObject> contributingObjects) {
  138. Restrictions res = Restrictions.Empty;
  139. if (contributingObjects != null) {
  140. foreach (MetaObject mo in contributingObjects) {
  141. if (mo != null) {
  142. res = res.Merge(mo.Restrictions);
  143. }
  144. }
  145. }
  146. return res;
  147. }
  148. public Expression CreateTest() {
  149. // TODO: Currently totally unoptimized and unordered
  150. Expression test = null;
  151. foreach (Restriction r in _restrictions) {
  152. Expression one;
  153. switch (r.Kind) {
  154. case Restriction.RestrictionKind.Type:
  155. one = CreateTypeRestriction(r.Expression, r.Type);
  156. break;
  157. case Restriction.RestrictionKind.Instance:
  158. one = CreateInstanceRestriction(r.Expression, r.Instance);
  159. break;
  160. case Restriction.RestrictionKind.Custom:
  161. one = r.Expression;
  162. break;
  163. default:
  164. throw new InvalidOperationException();
  165. }
  166. if (one != null) {
  167. if (test == null) {
  168. test = one;
  169. } else {
  170. test = Expression.AndAlso(test, one);
  171. }
  172. }
  173. }
  174. return test ?? Expression.True();
  175. }
  176. /// <summary>
  177. /// Creates one type identity test
  178. /// </summary>
  179. private static Expression CreateTypeRestriction(Expression expression, Type rt) {
  180. Type ct = expression.Type;
  181. if (ct == rt) {
  182. if (ct.IsValueType) {
  183. // No test necessary for value types
  184. return null;
  185. }
  186. if (ct.IsSealed) {
  187. // Sealed type is easy, just check for null
  188. return Expression.NotEqual(expression, Expression.Null());
  189. }
  190. }
  191. if (rt == typeof(None)) {
  192. return Expression.Equal(expression, Expression.Null(expression.Type));
  193. }
  194. return Expression.AndAlso(
  195. Expression.NotEqual(expression, Expression.Null()),
  196. Expression.Equal(
  197. Expression.Call(
  198. Expression.ConvertHelper(expression, typeof(object)),
  199. typeof(object).GetMethod("GetType")
  200. ),
  201. Expression.Constant(rt)
  202. )
  203. );
  204. }
  205. private static Expression CreateInstanceRestriction(Expression expression, object value) {
  206. if (value == null) {
  207. return Expression.Equal(
  208. expression,
  209. Expression.Null(expression.Type)
  210. );
  211. }
  212. return Expression.Equal(
  213. expression,
  214. Expression.Property(
  215. Expression.Constant(new WeakReference(value)),
  216. typeof(WeakReference).GetProperty("Target")
  217. )
  218. );
  219. }
  220. }
  221. }