PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Actions/ConditionalBuilder.cs

https://bitbucket.org/stefanrusek/xronos
C# | 130 lines | 78 code | 14 blank | 38 comment | 11 complexity | c2460a24b0cdc56ab6cbf839a379db6f 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 CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. #if CODEPLEX_40
  22. using System.Linq.Expressions;
  23. using System.Dynamic;
  24. #else
  25. using Microsoft.Linq.Expressions;
  26. using Microsoft.Scripting;
  27. #endif
  28. using Microsoft.Scripting.Utils;
  29. using AstUtils = Microsoft.Scripting.Ast.Utils;
  30. namespace Microsoft.Scripting.Actions {
  31. #if CODEPLEX_40
  32. using Ast = System.Linq.Expressions.Expression;
  33. #else
  34. using Ast = Microsoft.Linq.Expressions.Expression;
  35. #endif
  36. /// <summary>
  37. /// Builds up a series of conditionals when the False clause isn't yet known. We can
  38. /// keep appending conditions and if true's. Each subsequent true branch becomes the
  39. /// false branch of the previous condition and body. Finally a non-conditional terminating
  40. /// branch must be added.
  41. /// </summary>
  42. class ConditionalBuilder {
  43. private readonly List<Expression> _conditions = new List<Expression>();
  44. private readonly List<Expression> _bodies = new List<Expression>();
  45. private readonly List<ParameterExpression> _variables = new List<ParameterExpression>();
  46. private Expression _body;
  47. private BindingRestrictions _restrictions = BindingRestrictions.Empty;
  48. /// <summary>
  49. /// Adds a new conditional and body. The first call this becomes the top-level
  50. /// conditional, subsequent calls will have it added as false statement of the
  51. /// previous conditional.
  52. /// </summary>
  53. public void AddCondition(Expression condition, Expression body) {
  54. Assert.NotNull(condition, body);
  55. _conditions.Add(condition);
  56. _bodies.Add(body);
  57. }
  58. /// <summary>
  59. /// Adds the non-conditional terminating node.
  60. /// </summary>
  61. public void FinishCondition(Expression body) {
  62. if (_body != null) throw new InvalidOperationException();
  63. for (int i = _bodies.Count - 1; i >= 0; i--) {
  64. Type t = _bodies[i].Type;
  65. if (t != body.Type) {
  66. if (t.IsSubclassOf(body.Type)) {
  67. // subclass
  68. t = body.Type;
  69. } else if (body.Type.IsSubclassOf(t)) {
  70. // keep t
  71. } else {
  72. // incompatible, both go to object
  73. t = typeof(object);
  74. }
  75. }
  76. body = Ast.Condition(
  77. _conditions[i],
  78. AstUtils.Convert(_bodies[i], t),
  79. AstUtils.Convert(body, t)
  80. );
  81. }
  82. _body = Ast.Block(
  83. _variables,
  84. body
  85. );
  86. }
  87. public BindingRestrictions Restrictions {
  88. get {
  89. return _restrictions;
  90. }
  91. set {
  92. ContractUtils.RequiresNotNull(value, "value");
  93. _restrictions = value;
  94. }
  95. }
  96. /// <summary>
  97. /// Gets the resulting meta object for the full body. FinishCondition
  98. /// must have been called.
  99. /// </summary>
  100. public DynamicMetaObject GetMetaObject(params DynamicMetaObject[] types) {
  101. if (_body == null) {
  102. throw new InvalidOperationException("FinishCondition should have been called");
  103. }
  104. return new DynamicMetaObject(
  105. _body,
  106. BindingRestrictions.Combine(types).Merge(Restrictions)
  107. );
  108. }
  109. /// <summary>
  110. /// Adds a variable which will be scoped at the level of the final expression.
  111. /// </summary>
  112. public void AddVariable(ParameterExpression var) {
  113. _variables.Add(var);
  114. }
  115. }
  116. }