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

/DICK.B1/IronPython/Runtime/Binding/ConditionalBuilder.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 175 lines | 106 code | 25 blank | 44 comment | 14 complexity | 96a78b59e9f0ea5b9dc9a65e87c4a30d MD5 | raw 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. #if !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Text;
  23. using System.Dynamic;
  24. namespace IronPython.Runtime.Binding {
  25. using Ast = Expression;
  26. using AstUtils = Microsoft.Scripting.Ast.Utils;
  27. /// <summary>
  28. /// Builds up a series of conditionals when the False clause isn't yet known. We can
  29. /// keep appending conditions and if true's. Each subsequent true branch becomes the
  30. /// false branch of the previous condition and body. Finally a non-conditional terminating
  31. /// branch must be added.
  32. /// </summary>
  33. class ConditionalBuilder {
  34. private readonly DynamicMetaObjectBinder _action;
  35. private readonly List<Expression/*!*/>/*!*/ _conditions = new List<Expression>();
  36. private readonly List<Expression/*!*/>/*!*/ _bodies = new List<Expression>();
  37. private readonly List<ParameterExpression/*!*/>/*!*/ _variables = new List<ParameterExpression>();
  38. private Expression _body;
  39. private BindingRestrictions/*!*/ _restrictions = BindingRestrictions.Empty;
  40. private ParameterExpression _compareRetBool;
  41. private Type _retType;
  42. public ConditionalBuilder(DynamicMetaObjectBinder/*!*/ action) {
  43. _action = action;
  44. }
  45. public ConditionalBuilder() {
  46. }
  47. /// <summary>
  48. /// Adds a new conditional and body. The first call this becomes the top-level
  49. /// conditional, subsequent calls will have it added as false statement of the
  50. /// previous conditional.
  51. /// </summary>
  52. public void AddCondition(Expression/*!*/ condition, Expression/*!*/ body) {
  53. _conditions.Add(condition);
  54. _bodies.Add(body);
  55. }
  56. /// <summary>
  57. /// Adds a new condition to the last added body / condition.
  58. /// </summary>
  59. public void AddCondition(Expression condition) {
  60. if (_body != null) {
  61. AddCondition(condition, _body);
  62. _body = null;
  63. } else {
  64. _conditions[_conditions.Count - 1] = Ast.AndAlso(
  65. _conditions[_conditions.Count - 1],
  66. condition);
  67. }
  68. }
  69. /// <summary>
  70. /// Adds the non-conditional terminating node.
  71. /// </summary>
  72. public void FinishCondition(Expression/*!*/ body) {
  73. FinishCondition(body, typeof(object));
  74. }
  75. public void FinishCondition(Expression/*!*/ body, Type retType) {
  76. if (_body != null) throw new InvalidOperationException();
  77. _body = body;
  78. _retType = retType;
  79. }
  80. public ParameterExpression CompareRetBool {
  81. get {
  82. if (_compareRetBool == null) {
  83. _compareRetBool = Expression.Variable(typeof(bool), "compareRetBool");
  84. AddVariable(_compareRetBool);
  85. }
  86. return _compareRetBool;
  87. }
  88. }
  89. public BindingRestrictions Restrictions {
  90. get {
  91. return _restrictions;
  92. }
  93. set {
  94. _restrictions = value;
  95. }
  96. }
  97. public DynamicMetaObjectBinder Action {
  98. get {
  99. return _action;
  100. }
  101. }
  102. /// <summary>
  103. /// Returns true if no conditions have been added
  104. /// </summary>
  105. public bool NoConditions {
  106. get {
  107. return _conditions.Count == 0;
  108. }
  109. }
  110. /// <summary>
  111. /// Returns true if a final, non-conditional, body has been added.
  112. /// </summary>
  113. public bool IsFinal {
  114. get {
  115. return _body != null;
  116. }
  117. }
  118. /// <summary>
  119. /// Gets the resulting meta object for the full body. FinishCondition
  120. /// must have been called.
  121. /// </summary>
  122. public DynamicMetaObject/*!*/ GetMetaObject(params DynamicMetaObject/*!*/[]/*!*/ types) {
  123. if (_body == null) {
  124. throw new InvalidOperationException("FinishCondition not called before GetMetaObject");
  125. }
  126. Expression body = _body;
  127. for (int i = _bodies.Count - 1; i >= 0; i--) {
  128. body = Ast.Condition(
  129. _conditions[i],
  130. AstUtils.Convert(_bodies[i], _retType),
  131. AstUtils.Convert(body, _retType)
  132. );
  133. }
  134. body = Ast.Block(_variables, body);
  135. return new DynamicMetaObject(
  136. body,
  137. BindingRestrictions.Combine(types)
  138. );
  139. }
  140. /// <summary>
  141. /// Adds a variable which will be scoped at the level of the final expression.
  142. /// </summary>
  143. public void AddVariable(ParameterExpression/*!*/ var) {
  144. if (_body != null) {
  145. throw new InvalidOperationException("Variables must be added before calling FinishCondition");
  146. }
  147. _variables.Add(var);
  148. }
  149. }
  150. }