/Microsoft.Scripting/Actions/ConditionalBuilder.cs
C# | 130 lines | 78 code | 14 blank | 38 comment | 11 complexity | c2460a24b0cdc56ab6cbf839a379db6f MD5 | raw file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- #if CODEPLEX_40
- using System.Linq.Expressions;
- using System.Dynamic;
- #else
- using Microsoft.Linq.Expressions;
- using Microsoft.Scripting;
- #endif
- using Microsoft.Scripting.Utils;
- using AstUtils = Microsoft.Scripting.Ast.Utils;
-
- namespace Microsoft.Scripting.Actions {
- #if CODEPLEX_40
- using Ast = System.Linq.Expressions.Expression;
- #else
- using Ast = Microsoft.Linq.Expressions.Expression;
- #endif
-
- /// <summary>
- /// Builds up a series of conditionals when the False clause isn't yet known. We can
- /// keep appending conditions and if true's. Each subsequent true branch becomes the
- /// false branch of the previous condition and body. Finally a non-conditional terminating
- /// branch must be added.
- /// </summary>
- class ConditionalBuilder {
- private readonly List<Expression> _conditions = new List<Expression>();
- private readonly List<Expression> _bodies = new List<Expression>();
- private readonly List<ParameterExpression> _variables = new List<ParameterExpression>();
- private Expression _body;
- private BindingRestrictions _restrictions = BindingRestrictions.Empty;
-
- /// <summary>
- /// Adds a new conditional and body. The first call this becomes the top-level
- /// conditional, subsequent calls will have it added as false statement of the
- /// previous conditional.
- /// </summary>
- public void AddCondition(Expression condition, Expression body) {
- Assert.NotNull(condition, body);
-
- _conditions.Add(condition);
- _bodies.Add(body);
- }
-
- /// <summary>
- /// Adds the non-conditional terminating node.
- /// </summary>
- public void FinishCondition(Expression body) {
- if (_body != null) throw new InvalidOperationException();
-
- for (int i = _bodies.Count - 1; i >= 0; i--) {
- Type t = _bodies[i].Type;
- if (t != body.Type) {
- if (t.IsSubclassOf(body.Type)) {
- // subclass
- t = body.Type;
- } else if (body.Type.IsSubclassOf(t)) {
- // keep t
- } else {
- // incompatible, both go to object
- t = typeof(object);
- }
- }
-
- body = Ast.Condition(
- _conditions[i],
- AstUtils.Convert(_bodies[i], t),
- AstUtils.Convert(body, t)
- );
- }
-
- _body = Ast.Block(
- _variables,
- body
- );
- }
-
- public BindingRestrictions Restrictions {
- get {
- return _restrictions;
- }
- set {
- ContractUtils.RequiresNotNull(value, "value");
- _restrictions = value;
- }
- }
-
- /// <summary>
- /// Gets the resulting meta object for the full body. FinishCondition
- /// must have been called.
- /// </summary>
- public DynamicMetaObject GetMetaObject(params DynamicMetaObject[] types) {
- if (_body == null) {
- throw new InvalidOperationException("FinishCondition should have been called");
- }
-
- return new DynamicMetaObject(
- _body,
- BindingRestrictions.Combine(types).Merge(Restrictions)
- );
- }
-
- /// <summary>
- /// Adds a variable which will be scoped at the level of the final expression.
- /// </summary>
- public void AddVariable(ParameterExpression var) {
- _variables.Add(var);
- }
- }
-
- }