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