ExpressionQuoter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Scripting / Compiler / ExpressionQuoter.cs / 1305376 / ExpressionQuoter.cs

                            /* **************************************************************************** 
 *
 * 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.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Linq.Expressions;
using System.Linq.Expressions.Compiler;

namespace System.Runtime.CompilerServices { 
    public partial class RuntimeOps {
        ///  
        /// Quotes the provided expression tree. 
        /// 
        /// The expression to quote. 
        /// The hoisted local state provided by the compiler.
        /// The actual hoisted local values.
        /// The quoted expression.
        [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] 
        public static Expression Quote(Expression expression, object hoistedLocals, object[] locals) {
            Debug.Assert(hoistedLocals != null && locals != null); 
            var quoter = new ExpressionQuoter((HoistedLocals)hoistedLocals, locals); 
            return quoter.Visit(expression);
        } 

        /// 
        /// Combines two runtime variable lists and returns a new list.
        ///  
        /// The first list.
        /// The second list. 
        /// The index array indicating which list to get variables from. 
        /// The merged runtime variables.
        [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] 
        public static IRuntimeVariables MergeRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) {
            return new MergedRuntimeVariables(first, second, indexes);
        }
 
        // Modifies a quoted Expression instance by changing hoisted variables and
        // parameters into hoisted local references. The variable's StrongBox is 
        // burned as a constant, and all hoisted variables/parameters are rewritten 
        // as indexing expressions.
        // 
        // The behavior of Quote is indended to be like C# and VB expression quoting
        private sealed class ExpressionQuoter : ExpressionVisitor {
            private readonly HoistedLocals _scope;
            private readonly object[] _locals; 

            // A stack of variables that are defined in nested scopes. We search 
            // this first when resolving a variable in case a nested scope shadows 
            // one of our variable instances.
            private readonly Stack> _shadowedVars = new Stack>(); 

            internal ExpressionQuoter(HoistedLocals scope, object[] locals) {
                _scope = scope;
                _locals = locals; 
            }
 
            protected internal override Expression VisitLambda(Expression node) { 
                _shadowedVars.Push(new Set(node.Parameters));
                Expression b = Visit(node.Body); 
                _shadowedVars.Pop();
                if (b == node.Body) {
                    return node;
                } 
                return Expression.Lambda(b, node.Name, node.TailCall, node.Parameters);
            } 
 
            protected internal override Expression VisitBlock(BlockExpression node) {
                if (node.Variables.Count > 0) { 
                    _shadowedVars.Push(new Set(node.Variables));
                }
                var b = Visit(node.Expressions);
                if (node.Variables.Count > 0) { 
                    _shadowedVars.Pop();
                } 
                if (b == node.Expressions) { 
                    return node;
                } 
                return Expression.Block(node.Variables, b);
            }

            protected override CatchBlock VisitCatchBlock(CatchBlock node) { 
                if (node.Variable != null) {
                    _shadowedVars.Push(new Set(new[] { node.Variable })); 
                } 
                Expression b = Visit(node.Body);
                Expression f = Visit(node.Filter); 
                if (node.Variable != null) {
                    _shadowedVars.Pop();
                }
                if (b == node.Body && f == node.Filter) { 
                    return node;
                } 
                return Expression.MakeCatchBlock(node.Test, node.Variable, b, f); 
            }
 
            protected internal override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
                int count = node.Variables.Count;
                var boxes = new List();
                var vars = new List(); 
                var indexes = new int[count];
                for (int i = 0; i < count; i++) { 
                    IStrongBox box = GetBox(node.Variables[i]); 
                    if (box == null) {
                        indexes[i] = vars.Count; 
                        vars.Add(node.Variables[i]);
                    } else {
                        indexes[i] = -1 - boxes.Count;
                        boxes.Add(box); 
                    }
                } 
 
                // No variables were rewritten. Just return the original node
                if (boxes.Count == 0) { 
                    return node;
                }

                var boxesConst = Expression.Constant(new RuntimeVariables(boxes.ToArray()), typeof(IRuntimeVariables)); 
                // All of them were rewritten. Just return the array as a constant
                if (vars.Count == 0) { 
                    return boxesConst; 
                }
 
                // Otherwise, we need to return an object that merges them
                return Expression.Call(
                    typeof(RuntimeOps).GetMethod("MergeRuntimeVariables"),
                    Expression.RuntimeVariables(new TrueReadOnlyCollection(vars.ToArray())), 
                    boxesConst,
                    Expression.Constant(indexes) 
                ); 
            }
 
            protected internal override Expression VisitParameter(ParameterExpression node) {
                IStrongBox box = GetBox(node);
                if (box == null) {
                    return node; 
                }
                return Expression.Field(Expression.Constant(box), "Value"); 
            } 

            private IStrongBox GetBox(ParameterExpression variable) { 
                // Skip variables that are shadowed by a nested scope/lambda
                foreach (Set hidden in _shadowedVars) {
                    if (hidden.Contains(variable)) {
                        return null; 
                    }
                } 
 
                HoistedLocals scope = _scope;
                object[] locals = _locals; 
                while (true) {
                    int hoistIndex;
                    if (scope.Indexes.TryGetValue(variable, out hoistIndex)) {
                        return (IStrongBox)locals[hoistIndex]; 
                    }
                    scope = scope.Parent; 
                    if (scope == null) { 
                        break;
                    } 
                    locals = HoistedLocals.GetParent(locals);
                }

                // Unbound variable: an error should've been thrown already 
                // from VariableBinder
                throw ContractUtils.Unreachable; 
            } 
        }
 
        private sealed class RuntimeVariables : IRuntimeVariables {
            private readonly IStrongBox[] _boxes;

            internal RuntimeVariables(IStrongBox[] boxes) { 
                _boxes = boxes;
            } 
 
            int IRuntimeVariables.Count {
                get { return _boxes.Length; } 
            }

            object IRuntimeVariables.this[int index] {
                get { 
                    return _boxes[index].Value;
                } 
                set { 
                    _boxes[index].Value = value;
                } 
            }
        }

        ///  
        /// Provides a list of variables, supporing read/write of the values
        /// Exposed via RuntimeVariablesExpression 
        ///  
        private sealed class MergedRuntimeVariables : IRuntimeVariables {
            private readonly IRuntimeVariables _first; 
            private readonly IRuntimeVariables _second;

            // For reach item, the index into the first or second list
            // Positive values mean the first array, negative means the second 
            private readonly int[] _indexes;
 
            internal MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { 
                _first = first;
                _second = second; 
                _indexes = indexes;
            }

            public int Count { 
                get { return _indexes.Length; }
            } 
 
            public object this[int index] {
                get { 
                    index = _indexes[index];
                    return (index >= 0) ? _first[index] : _second[-1 - index];
                }
                set { 
                    index = _indexes[index];
                    if (index >= 0) { 
                        _first[index] = value; 
                    } else {
                        _second[-1 - index] = value; 
                    }
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/* **************************************************************************** 
 *
 * 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.
 *
 *
 * ***************************************************************************/ 

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Linq.Expressions;
using System.Linq.Expressions.Compiler;

namespace System.Runtime.CompilerServices { 
    public partial class RuntimeOps {
        ///  
        /// Quotes the provided expression tree. 
        /// 
        /// The expression to quote. 
        /// The hoisted local state provided by the compiler.
        /// The actual hoisted local values.
        /// The quoted expression.
        [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] 
        public static Expression Quote(Expression expression, object hoistedLocals, object[] locals) {
            Debug.Assert(hoistedLocals != null && locals != null); 
            var quoter = new ExpressionQuoter((HoistedLocals)hoistedLocals, locals); 
            return quoter.Visit(expression);
        } 

        /// 
        /// Combines two runtime variable lists and returns a new list.
        ///  
        /// The first list.
        /// The second list. 
        /// The index array indicating which list to get variables from. 
        /// The merged runtime variables.
        [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)] 
        public static IRuntimeVariables MergeRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) {
            return new MergedRuntimeVariables(first, second, indexes);
        }
 
        // Modifies a quoted Expression instance by changing hoisted variables and
        // parameters into hoisted local references. The variable's StrongBox is 
        // burned as a constant, and all hoisted variables/parameters are rewritten 
        // as indexing expressions.
        // 
        // The behavior of Quote is indended to be like C# and VB expression quoting
        private sealed class ExpressionQuoter : ExpressionVisitor {
            private readonly HoistedLocals _scope;
            private readonly object[] _locals; 

            // A stack of variables that are defined in nested scopes. We search 
            // this first when resolving a variable in case a nested scope shadows 
            // one of our variable instances.
            private readonly Stack> _shadowedVars = new Stack>(); 

            internal ExpressionQuoter(HoistedLocals scope, object[] locals) {
                _scope = scope;
                _locals = locals; 
            }
 
            protected internal override Expression VisitLambda(Expression node) { 
                _shadowedVars.Push(new Set(node.Parameters));
                Expression b = Visit(node.Body); 
                _shadowedVars.Pop();
                if (b == node.Body) {
                    return node;
                } 
                return Expression.Lambda(b, node.Name, node.TailCall, node.Parameters);
            } 
 
            protected internal override Expression VisitBlock(BlockExpression node) {
                if (node.Variables.Count > 0) { 
                    _shadowedVars.Push(new Set(node.Variables));
                }
                var b = Visit(node.Expressions);
                if (node.Variables.Count > 0) { 
                    _shadowedVars.Pop();
                } 
                if (b == node.Expressions) { 
                    return node;
                } 
                return Expression.Block(node.Variables, b);
            }

            protected override CatchBlock VisitCatchBlock(CatchBlock node) { 
                if (node.Variable != null) {
                    _shadowedVars.Push(new Set(new[] { node.Variable })); 
                } 
                Expression b = Visit(node.Body);
                Expression f = Visit(node.Filter); 
                if (node.Variable != null) {
                    _shadowedVars.Pop();
                }
                if (b == node.Body && f == node.Filter) { 
                    return node;
                } 
                return Expression.MakeCatchBlock(node.Test, node.Variable, b, f); 
            }
 
            protected internal override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) {
                int count = node.Variables.Count;
                var boxes = new List();
                var vars = new List(); 
                var indexes = new int[count];
                for (int i = 0; i < count; i++) { 
                    IStrongBox box = GetBox(node.Variables[i]); 
                    if (box == null) {
                        indexes[i] = vars.Count; 
                        vars.Add(node.Variables[i]);
                    } else {
                        indexes[i] = -1 - boxes.Count;
                        boxes.Add(box); 
                    }
                } 
 
                // No variables were rewritten. Just return the original node
                if (boxes.Count == 0) { 
                    return node;
                }

                var boxesConst = Expression.Constant(new RuntimeVariables(boxes.ToArray()), typeof(IRuntimeVariables)); 
                // All of them were rewritten. Just return the array as a constant
                if (vars.Count == 0) { 
                    return boxesConst; 
                }
 
                // Otherwise, we need to return an object that merges them
                return Expression.Call(
                    typeof(RuntimeOps).GetMethod("MergeRuntimeVariables"),
                    Expression.RuntimeVariables(new TrueReadOnlyCollection(vars.ToArray())), 
                    boxesConst,
                    Expression.Constant(indexes) 
                ); 
            }
 
            protected internal override Expression VisitParameter(ParameterExpression node) {
                IStrongBox box = GetBox(node);
                if (box == null) {
                    return node; 
                }
                return Expression.Field(Expression.Constant(box), "Value"); 
            } 

            private IStrongBox GetBox(ParameterExpression variable) { 
                // Skip variables that are shadowed by a nested scope/lambda
                foreach (Set hidden in _shadowedVars) {
                    if (hidden.Contains(variable)) {
                        return null; 
                    }
                } 
 
                HoistedLocals scope = _scope;
                object[] locals = _locals; 
                while (true) {
                    int hoistIndex;
                    if (scope.Indexes.TryGetValue(variable, out hoistIndex)) {
                        return (IStrongBox)locals[hoistIndex]; 
                    }
                    scope = scope.Parent; 
                    if (scope == null) { 
                        break;
                    } 
                    locals = HoistedLocals.GetParent(locals);
                }

                // Unbound variable: an error should've been thrown already 
                // from VariableBinder
                throw ContractUtils.Unreachable; 
            } 
        }
 
        private sealed class RuntimeVariables : IRuntimeVariables {
            private readonly IStrongBox[] _boxes;

            internal RuntimeVariables(IStrongBox[] boxes) { 
                _boxes = boxes;
            } 
 
            int IRuntimeVariables.Count {
                get { return _boxes.Length; } 
            }

            object IRuntimeVariables.this[int index] {
                get { 
                    return _boxes[index].Value;
                } 
                set { 
                    _boxes[index].Value = value;
                } 
            }
        }

        ///  
        /// Provides a list of variables, supporing read/write of the values
        /// Exposed via RuntimeVariablesExpression 
        ///  
        private sealed class MergedRuntimeVariables : IRuntimeVariables {
            private readonly IRuntimeVariables _first; 
            private readonly IRuntimeVariables _second;

            // For reach item, the index into the first or second list
            // Positive values mean the first array, negative means the second 
            private readonly int[] _indexes;
 
            internal MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { 
                _first = first;
                _second = second; 
                _indexes = indexes;
            }

            public int Count { 
                get { return _indexes.Length; }
            } 
 
            public object this[int index] {
                get { 
                    index = _indexes[index];
                    return (index >= 0) ? _first[index] : _second[-1 - index];
                }
                set { 
                    index = _indexes[index];
                    if (index >= 0) { 
                        _first[index] = value; 
                    } else {
                        _second[-1 - index] = value; 
                    }
                }
            }
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK