xronos /Microsoft.Scripting/Actions/ConditionalBuilder.cs

Language C# Lines 131
MD5 Hash c2460a24b0cdc56ab6cbf839a379db6f Estimated Cost $1,855 (why?)
Repository https://bitbucket.org/stefanrusek/xronos View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* ****************************************************************************
 *
 * 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);
        }
    }

}
Back to Top