VisualBasicHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / Microsoft / VisualBasic / Activities / VisualBasicHelper.cs / 1305376 / VisualBasicHelper.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace Microsoft.VisualBasic.Activities 
{
    using System; 
    using System.Activities; 
    using System.Activities.ExpressionParser;
    using System.CodeDom; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization; 
    using System.IO;
    using System.Linq; 
    using System.Linq.Expressions; 
    using System.Reflection;
    using System.Runtime; 
    using System.Runtime.Collections;
    using System.Text;
    using Microsoft.Compiler.VisualBasic;
    using System.Collections.ObjectModel; 
    using Microsoft.VisualBasic.CompilerServices;
 
    class VisualBasicHelper 
    {
        // the following assemblies are provided to the compiler by default 
        // items are public so the decompiler knows which assemblies it doesn't need to reference for interfaces
        public static readonly HashSet DefaultReferencedAssemblies = new HashSet
            {
                typeof(int).Assembly, // mscorlib 
                typeof(CodeTypeDeclaration).Assembly, // System
                typeof(Expression).Assembly,             // System.Core 
                typeof(Microsoft.VisualBasic.Strings).Assembly,  // Microsoft.VisualBasic 
                typeof(Activity).Assembly  // System.Activities
            }; 

        // cache for Assembly ==> AssemblyName
        // Assembly.GetName() is very very expensive
        const int assemblyToAssemblyNameCacheInitSize = 100; 
        static object assemblyToAssemblyNameCacheLock = new object();
        static Hashtable assemblyToAssemblyNameCache; 
 
        // this gets the cached AssemblyName
        // if not found, it caches the Assembly and creates its AssemblyName set it as the value 
        // make sure you don't ever call this method for dynamic assemblies that need to be collected
        public static AssemblyName GetFastAssemblyName(Assembly assembly)
        {
            if (assemblyToAssemblyNameCache == null) 
            {
                lock (assemblyToAssemblyNameCacheLock) 
                { 
                    if (assemblyToAssemblyNameCache == null)
                    { 
                        assemblyToAssemblyNameCache = new Hashtable(assemblyToAssemblyNameCacheInitSize);
                    }
                }
            } 
            AssemblyName assemblyName = assemblyToAssemblyNameCache[assembly] as AssemblyName;
            if (assemblyName != null) 
            { 
                return assemblyName;
            } 

            assemblyName = new AssemblyName(assembly.FullName);
            lock (assemblyToAssemblyNameCacheLock)
            { 
                assemblyToAssemblyNameCache[assembly] = assemblyName;
            } 
            return assemblyName; 
        }
 
        // cache for type's all base types, interfaces, generic arguments, element type
        // HopperCache is a psuedo-MRU cache
        const int typeReferenceCacheMaxSize = 100;
        static object typeReferenceCacheLock = new object(); 
        static HopperCache typeReferenceCache = new HopperCache(typeReferenceCacheMaxSize, false);
 
        const int AssemblyCacheInitialSize = 100; 
        static Hashtable assemblyCache;
        static object assemblyCacheLock = new object(); 

        static Assembly GetAssembly(AssemblyName assemblyName)
        {
            // the following assembly resolution logic 
            // emulates the Xaml's assembly resolution logic as closely as possible.
            // Should Xaml's assembly resolution logic ever change, this code needs update as well. 
            // please see XamlSchemaContext.ResolveAssembly() 

            if (assemblyCache == null) 
            {
                lock (assemblyCacheLock)
                {
                    if (assemblyCache == null) 
                    {
                        assemblyCache = new Hashtable(AssemblyCacheInitialSize, new AssemblyNameEqualityComparer()); 
                    } 
                }
            } 

            Assembly assembly = assemblyCache[assemblyName] as Assembly;
            if (assembly != null)
            { 
                return assembly;
            } 
 
            // search current AppDomain first
            // this for-loop part is to ensure that 
            // loose AssemblyNames get resolved in the same way
            // as Xaml would do.  that is to find the first match
            // found starting from the end of the array of Assemblies
            // returned by AppDomain.GetAssemblies() 
            Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
            for (int i = currentAssemblies.Length - 1; i >= 0; i--) 
            { 
                Assembly curAsm = currentAssemblies[i];
                if (curAsm.IsDynamic) 
                {
                    // ignore dynamic assemblies
                    continue;
                } 

                AssemblyName curAsmName = GetFastAssemblyName(curAsm); 
                Version curVersion = curAsmName.Version; 
                CultureInfo curCulture = curAsmName.CultureInfo;
                byte[] curKeyToken = curAsmName.GetPublicKeyToken(); 

                Version reqVersion = assemblyName.Version;
                CultureInfo reqCulture = assemblyName.CultureInfo;
                byte[] reqKeyToken = assemblyName.GetPublicKeyToken(); 

                if ((String.Compare(curAsmName.Name, assemblyName.Name, StringComparison.OrdinalIgnoreCase) == 0) && 
                         (reqVersion == null || reqVersion.Equals(curVersion)) && 
                         (reqCulture == null || reqCulture.Equals(curCulture)) &&
                         (reqKeyToken == null || AssemblyNameEqualityComparer.IsSameKeyToken(reqKeyToken, curKeyToken))) 
                {
                    lock (assemblyCacheLock)
                    {
                        assemblyCache[assemblyName] = curAsm; 
                        return curAsm;
                    } 
                } 
            }
 
            assembly = LoadAssembly(assemblyName);
            if (assembly != null)
            {
                lock (assemblyCacheLock) 
                {
                    assemblyCache[assemblyName] = assembly; 
                } 
            }
            return assembly; 
        }

        const int HostedCompilerCacheSize = 10;
        static Dictionary, HostedCompiler> HostedCompilerCache; 
        static HostedCompiler GetCachedHostedCompiler(HashSet assemblySet)
        { 
            if (HostedCompilerCache == null) 
            {
                // HostedCompiler Cache Initializatoin... 
                IEqualityComparer> AssemblySetEqualityComparer = HashSet.CreateSetComparer();
                HostedCompilerCache = new Dictionary, HostedCompiler>(HostedCompilerCacheSize, AssemblySetEqualityComparer);
            }
 
            lock (HostedCompilerCache)
            { 
                HostedCompiler hcompiler; 
                if (HostedCompilerCache.TryGetValue(assemblySet, out hcompiler))
                { 
                    return hcompiler;
                }

                if (HostedCompilerCache.Count >= HostedCompilerCacheSize) 
                {
                    // kick one out of the cache 
                    HashSet keyToRemove = HostedCompilerCache.Keys.ElementAtOrDefault>(1); 
                    HostedCompilerCache.Remove(keyToRemove);
                } 
                hcompiler = new HostedCompiler(assemblySet.ToList());
                HostedCompilerCache[assemblySet] = hcompiler;
                return hcompiler;
            } 
        }
 
        string textToCompile; 
        HashSet referencedAssemblies;
        HashSet namespaceImports; 
        LocationReferenceEnvironment environment;
        CodeActivityMetadata? metadata;

        public VisualBasicHelper(string expressionText, HashSet refAssemNames, HashSet namespaceImportsNames) 
            : this(expressionText)
        { 
            Initialize(refAssemNames, namespaceImportsNames); 
        }
 
        VisualBasicHelper(string expressionText)
        {
            this.textToCompile = expressionText;
        } 

        public string TextToCompile { get { return this.textToCompile; } } 
 
        void Initialize(HashSet refAssemNames, HashSet namespaceImportsNames)
        { 
            this.namespaceImports = namespaceImportsNames;

            foreach (AssemblyName assemblyName in refAssemNames)
            { 
                if (this.referencedAssemblies == null)
                { 
                    this.referencedAssemblies = new HashSet(); 
                }
                Assembly loaded = GetAssembly(assemblyName); 
                if (loaded != null)
                {
                    this.referencedAssemblies.Add(loaded);
                } 
            }
        } 
 
        public static HashSet GetAllImportReferences(Activity root)
        { 
            VisualBasicSettings rootVBSettings = null;

            if (root != null)
            { 
                rootVBSettings = VisualBasic.GetSettings(root);
            } 
 
            // start with our defaults
            HashSet localImportReferences = new HashSet(VisualBasicSettings.Default.ImportReferences); 

            if (rootVBSettings != null)
            {
                // Xaml file level 
                localImportReferences.UnionWith(rootVBSettings.ImportReferences);
            } 
 
            return localImportReferences;
        } 

        public static Expression> Compile(string expressionText, CodeActivityMetadata metadata)
        {
            HashSet localImportReferences = GetAllImportReferences(metadata.Environment.Root); 
            VisualBasicHelper helper = new VisualBasicHelper(expressionText);
            HashSet localReferenceAssemblies = new HashSet(); 
            HashSet localImports = new HashSet(); 
            foreach (VisualBasicImportReference importReference in localImportReferences)
            { 
                if (importReference.EarlyBoundAssembly != null)
                {
                    // we have an early bound assembly
                    // this is an indication that we are in the 
                    // context of "compiled Xaml"
                    // directly add the Assembly to the list 
                    // so that we don't have to go through 
                    // the assembly resolution process
                    localImports.Add(importReference.Import); 
                    if (helper.referencedAssemblies == null)
                    {
                        helper.referencedAssemblies = new HashSet();
                    } 
                    helper.referencedAssemblies.Add(importReference.EarlyBoundAssembly);
                    continue; 
                } 

                if (importReference.AssemblyName != null) 
                {
                    localReferenceAssemblies.Add(importReference.AssemblyName);
                }
                localImports.Add(importReference.Import); 
            }
 
            helper.Initialize(localReferenceAssemblies, localImports); 
            return helper.Compile(metadata);
        } 

        public LambdaExpression CompileNonGeneric(LocationReferenceEnvironment environment)
        {
            Microsoft.Compiler.VisualBasic.CompilerResults results; 
            this.environment = environment;
            if (this.referencedAssemblies == null) 
            { 
                this.referencedAssemblies = new HashSet();
            } 
            this.referencedAssemblies.UnionWith(DefaultReferencedAssemblies);

            List importList = new List();
            foreach (string namespaceImport in this.namespaceImports) 
            {
                if (!String.IsNullOrEmpty(namespaceImport)) 
                { 
                    importList.Add(new Import(namespaceImport));
                } 
            }

            VisualBasicScriptAndTypeScope scriptAndTypeScope = new VisualBasicScriptAndTypeScope(
                this.environment, 
                this.referencedAssemblies.ToList());
 
            IImportScope importScope = new VisualBasicImportScope(importList); 
            CompilerOptions options = new CompilerOptions();
            options.OptionStrict = OptionStrictSetting.On; 
            CompilerContext context = new CompilerContext(scriptAndTypeScope, scriptAndTypeScope, importScope, options);

            HostedCompiler compiler = GetCachedHostedCompiler(this.referencedAssemblies);
 
            lock (compiler)
            { 
                try 
                {
                    results = compiler.CompileExpression(this.textToCompile, context); 
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e)) 
                    {
                        throw; 
                    } 

                    FxTrace.Exception.TraceUnhandledException(e); 
                    throw;
                }
            }
 
            if (scriptAndTypeScope.ErrorMessage != null)
            { 
                throw FxTrace.Exception.AsError(new SourceExpressionException(SR.CompilerErrorSpecificExpression(textToCompile, scriptAndTypeScope.ErrorMessage))); 
            }
 
            if (results.Errors != null && results.Errors.Count > 0)
            {
                // this expression has problems, so report them
                StringBuilder errorString = new StringBuilder(); 
                errorString.AppendLine();
                foreach (Error error in results.Errors) 
                { 
                    errorString.AppendLine(error.Description);
                } 
                throw FxTrace.Exception.AsError(new SourceExpressionException(SR.CompilerErrorSpecificExpression(textToCompile, errorString.ToString())));
            }

            // replace the field references with variable references to our dummy variables 
            // and rewrite lambda.body.Type to equal the lambda return type T
            LambdaExpression lambda = results.CodeBlock; 
            if (lambda == null) 
            {
                // ExpressionText was either an empty string or Null 
                // we return null which eventually evaluates to default(TResult) at execution time.
                return null;
            }
            return Expression.Lambda(lambda.Type, Rewrite(lambda.Body, null), lambda.Parameters); 
        }
 
        public Expression> Compile(CodeActivityMetadata metadata) 
        {
            this.metadata = metadata; 

            return Compile(metadata.Environment);
        }
 
        // Soft-Link: This method is called through reflection by VisualBasicDesignerHelper.
        public Expression> Compile(LocationReferenceEnvironment environment) 
        { 
            Microsoft.Compiler.VisualBasic.CompilerResults results;
            Type lambdaReturnType = typeof(T); 

            this.environment = environment;
            if (this.referencedAssemblies == null)
            { 
                this.referencedAssemblies = new HashSet();
            } 
            this.referencedAssemblies.UnionWith(DefaultReferencedAssemblies); 

            List importList = new List(); 
            foreach (string namespaceImport in this.namespaceImports)
            {
                if (!String.IsNullOrEmpty(namespaceImport))
                { 
                    importList.Add(new Import(namespaceImport));
                } 
            } 

            // ensure the return type's assembly is added to ref assembly list 
            HashSet allBaseTypes = null;
            EnsureTypeReferenced(lambdaReturnType, ref allBaseTypes);
            foreach (Type baseType in allBaseTypes)
            { 
                // allBaseTypes list always contains lambdaReturnType
                this.referencedAssemblies.Add(baseType.Assembly); 
            } 

            VisualBasicScriptAndTypeScope scriptAndTypeScope = new VisualBasicScriptAndTypeScope( 
                this.environment,
                this.referencedAssemblies.ToList());

            IImportScope importScope = new VisualBasicImportScope(importList); 
            CompilerOptions options = new CompilerOptions();
            options.OptionStrict = OptionStrictSetting.On; 
            CompilerContext context = new CompilerContext(scriptAndTypeScope, scriptAndTypeScope, importScope, options); 
            HostedCompiler compiler = GetCachedHostedCompiler(this.referencedAssemblies);
 
            lock (compiler)
            {
                try
                { 
                    results = compiler.CompileExpression(this.textToCompile, context, lambdaReturnType);
                } 
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e)) 
                    {
                        throw;
                    }
 
                    // We never want to end up here, Compiler bugs needs to be fixed.
                    FxTrace.Exception.TraceUnhandledException(e); 
                    throw; 
                }
            } 

            if (scriptAndTypeScope.ErrorMessage != null)
            {
                throw FxTrace.Exception.AsError(new SourceExpressionException(SR.CompilerErrorSpecificExpression(textToCompile, scriptAndTypeScope.ErrorMessage))); 
            }
 
            if (results.Errors != null && results.Errors.Count > 0) 
            {
                // this expression has problems, so report them 
                StringBuilder errorString = new StringBuilder();
                errorString.AppendLine();
                foreach (Error error in results.Errors)
                { 
                    errorString.AppendLine(error.Description);
                } 
                throw FxTrace.Exception.AsError(new SourceExpressionException(SR.CompilerErrorSpecificExpression(textToCompile, errorString.ToString()))); 
            }
 
            // replace the field references with variable references to our dummy variables
            // and rewrite lambda.body.Type to equal the lambda return type T
            LambdaExpression lambda = results.CodeBlock;
            if (lambda == null) 
            {
                // ExpressionText was either an empty string or Null 
                // we return null which eventually evaluates to default(TResult) at execution time. 
                return null;
            } 

            Expression finalBody = Rewrite(lambda.Body, null);

            Fx.Assert(finalBody.Type == lambdaReturnType, "Compiler generated ExpressionTree return type doesn't match the target return type"); 

            // convert it into the our expected lambda format (context => ...) 
            return Expression.Lambda>(finalBody, 
                FindParameter(finalBody) ?? ExpressionUtilities.RuntimeContextParameter);
        } 

#pragma warning disable 618
        [SuppressMessage(
            "Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", 
            MessageId = "System.Reflection.Assembly.LoadWithPartialName",
            Justification = "Assembly.LoadWithPartialName is the only method with the right behavior.")] 
        static Assembly LoadAssembly(AssemblyName assemblyName) 
        {
            Assembly loaded = null; 

            Fx.Assert(assemblyName.Name != null, "AssemblyName.Name cannot be null");
            byte[] publicKeyToken = assemblyName.GetPublicKeyToken();
            if (assemblyName.Version != null || assemblyName.CultureInfo != null || publicKeyToken != null) 
            {
                // Assembly.Load(string) 
                try 
                {
                    loaded = Assembly.Load(assemblyName.FullName); 
                }
                catch (Exception ex)
                {
                    if (ex is FileNotFoundException || 
                        ex is FileLoadException ||
                        (ex is TargetInvocationException && 
                        (((TargetInvocationException)ex).InnerException is FileNotFoundException || 
                        ((TargetInvocationException)ex).InnerException is FileNotFoundException)))
                    { 
                        loaded = null;
                        FxTrace.Exception.AsWarning(ex);
                    }
                    else 
                    {
                        throw; 
                    } 
                }
            } 
            else
            {
                // partial assembly name
                loaded = Assembly.LoadWithPartialName(assemblyName.FullName); 
            }
            return loaded; 
        } 
#pragma warning restore 618
 
        Expression Rewrite(Expression expression, ReadOnlyCollection lambdaParameters)
        {
            if (expression == null)
            { 
                return null;
            } 
            switch (expression.NodeType) 
            {
                case ExpressionType.Add: 
                case ExpressionType.AddChecked:
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                case ExpressionType.Coalesce: 
                case ExpressionType.Divide:
                case ExpressionType.Equal: 
                case ExpressionType.ExclusiveOr: 
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual: 
                case ExpressionType.LeftShift:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.Modulo: 
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked: 
                case ExpressionType.NotEqual: 
                case ExpressionType.Or:
                case ExpressionType.OrElse: 
                case ExpressionType.Power:
                case ExpressionType.RightShift:
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked: 
                    BinaryExpression binaryExpression = (BinaryExpression)expression;
                    return Expression.MakeBinary( 
                        binaryExpression.NodeType, 
                        Rewrite(binaryExpression.Left, lambdaParameters),
                        Rewrite(binaryExpression.Right, lambdaParameters), 
                        binaryExpression.IsLiftedToNull,
                        binaryExpression.Method,
                        (LambdaExpression)Rewrite(binaryExpression.Conversion, lambdaParameters));
 
                case ExpressionType.Conditional:
                    ConditionalExpression conditional = (ConditionalExpression)expression; 
                    return Expression.Condition( 
                        Rewrite(conditional.Test, lambdaParameters),
                        Rewrite(conditional.IfTrue, lambdaParameters), 
                        Rewrite(conditional.IfFalse, lambdaParameters));

                case ExpressionType.Constant:
                    return expression; 

                case ExpressionType.Invoke: 
                    InvocationExpression invocation = (InvocationExpression)expression; 
                    return Expression.Invoke(
                        Rewrite(invocation.Expression, lambdaParameters), 
                        from a in invocation.Arguments select Rewrite(a, lambdaParameters));

                case ExpressionType.Lambda:
                    LambdaExpression lambda = (LambdaExpression)expression; 
                    return Expression.Lambda(
                        lambda.Type, 
                        Rewrite(lambda.Body, lambda.Parameters), 
                        lambda.Parameters);
 
                case ExpressionType.ListInit:
                    ListInitExpression listInit = (ListInitExpression)expression;
                    return Expression.ListInit(
                        (NewExpression)Rewrite(listInit.NewExpression, lambdaParameters), 
                        from ei in listInit.Initializers
                        select Expression.ElementInit( 
                        ei.AddMethod, 
                        from arg in ei.Arguments select Rewrite(arg, lambdaParameters)));
 
                case ExpressionType.Parameter:
                    ParameterExpression variableExpression = (ParameterExpression)expression;
                    {
                        if (lambdaParameters != null && lambdaParameters.Contains(variableExpression)) 
                        {
                            return variableExpression; 
                        } 

                        string name = variableExpression.Name; 
                        LocationReferenceEnvironment currentEnvironment = this.environment;
                        while (currentEnvironment != null)
                        {
                            foreach (LocationReference reference in currentEnvironment.GetLocationReferences()) 
                            {
                                if (string.Equals(reference.Name, name, StringComparison.OrdinalIgnoreCase)) 
                                { 
                                    LocationReference finalReference = reference;
                                    if (this.metadata != null) 
                                    {
                                        CodeActivityMetadata localMetadata = this.metadata.Value;

                                        LocationReference inlinedReference; 
                                        if (localMetadata.TryGetInlinedLocationReference(reference, out inlinedReference))
                                        { 
                                            finalReference = inlinedReference; 
                                        }
                                    } 

                                    return ExpressionUtilities.CreateIdentifierExpression(finalReference);
                                }
                            } 
                            currentEnvironment = currentEnvironment.Parent;
 
                        } 

                        // if we are here, this variableExpression is a temp variable 
                        // generated by the compiler.
                        return variableExpression;
                    }
 
                case ExpressionType.MemberAccess:
                    MemberExpression memberExpression = (MemberExpression)expression; 
                    return Expression.MakeMemberAccess( 
                        Rewrite(memberExpression.Expression, lambdaParameters),
                        memberExpression.Member); 

                case ExpressionType.MemberInit:
                    MemberInitExpression memberInit = (MemberInitExpression)expression;
                    return Expression.MemberInit( 
                        (NewExpression)Rewrite(memberInit.NewExpression, lambdaParameters),
                        from b in memberInit.Bindings select Rewrite(b, lambdaParameters)); 
 
                case ExpressionType.ArrayIndex:
                    // ArrayIndex can be a MethodCallExpression or a BinaryExpression 
                    MethodCallExpression arrayIndex = expression as MethodCallExpression;
                    if (arrayIndex != null)
                    {
                        return Expression.ArrayIndex( 
                            Rewrite(arrayIndex.Object, lambdaParameters),
                            from a in arrayIndex.Arguments select Rewrite(a, lambdaParameters)); 
                    } 
                    BinaryExpression alternateIndex = (BinaryExpression)expression;
                    return Expression.ArrayIndex( 
                        Rewrite(alternateIndex.Left, lambdaParameters),
                        Rewrite(alternateIndex.Right, lambdaParameters));

                case ExpressionType.Call: 
                    MethodCallExpression methodCall = (MethodCallExpression)expression;
                    return Expression.Call( 
                        Rewrite(methodCall.Object, lambdaParameters), 
                        methodCall.Method,
                        from a in methodCall.Arguments select Rewrite(a, lambdaParameters)); 

                case ExpressionType.NewArrayInit:
                    NewArrayExpression newArray = (NewArrayExpression)expression;
                    return Expression.NewArrayInit( 
                        newArray.Type.GetElementType(),
                        from e in newArray.Expressions select Rewrite(e, lambdaParameters)); 
 
                case ExpressionType.NewArrayBounds:
                    NewArrayExpression newArrayBounds = (NewArrayExpression)expression; 
                    return Expression.NewArrayBounds(
                        newArrayBounds.Type.GetElementType(),
                        from e in newArrayBounds.Expressions select Rewrite(e, lambdaParameters));
 
                case ExpressionType.New:
                    NewExpression newExpression = (NewExpression)expression; 
                    if (newExpression.Constructor == null) 
                    {
                        // must be creating a valuetype 
                        Fx.Assert(newExpression.Arguments.Count == 0, "NewExpression with null Constructor but some arguments");
                        return expression;
                    }
                    return Expression.New( 
                        newExpression.Constructor,
                        from a in newExpression.Arguments select Rewrite(a, lambdaParameters)); 
 
                case ExpressionType.TypeIs:
                    TypeBinaryExpression typeBinary = (TypeBinaryExpression)expression; 
                    return Expression.TypeIs(
                        Rewrite(typeBinary.Expression, lambdaParameters),
                        typeBinary.TypeOperand);
 
                case ExpressionType.ArrayLength:
                case ExpressionType.Convert: 
                case ExpressionType.ConvertChecked: 
                case ExpressionType.Negate:
                case ExpressionType.NegateChecked: 
                case ExpressionType.Not:
                case ExpressionType.Quote:
                case ExpressionType.TypeAs:
                    UnaryExpression unary = (UnaryExpression)expression; 
                    return Expression.MakeUnary(
                        unary.NodeType, 
                        Rewrite(unary.Operand, lambdaParameters), 
                        unary.Type,
                        unary.Method); 

                case ExpressionType.UnaryPlus:
                    UnaryExpression unaryPlus = (UnaryExpression)expression;
                    return Expression.UnaryPlus( 
                        Rewrite(unaryPlus.Operand, lambdaParameters),
                        unaryPlus.Method); 
 
                // Expression Tree V2.0 types. This is due to the hosted VB compiler generating ET V2.0 nodes
 
                case ExpressionType.Block:
                    BlockExpression block = (BlockExpression)expression;
                    List parameterList = new List();
                    foreach (ParameterExpression e in block.Variables) 
                    {
                        parameterList.Add((ParameterExpression)Rewrite(e, lambdaParameters)); 
                    } 
                    List expressionList = new List();
                    foreach (Expression e in block.Expressions) 
                    {
                        expressionList.Add(Rewrite(e, lambdaParameters));
                    }
                    return Expression.Block(parameterList, expressionList); 

                case ExpressionType.Assign: 
                    BinaryExpression assign = (BinaryExpression)expression; 
                    return Expression.Assign(Rewrite(assign.Left, lambdaParameters), Rewrite(assign.Right, lambdaParameters));
            } 

            Fx.Assert("Don't understand expression type " + expression.NodeType);
            return expression;
        } 

        MemberBinding Rewrite(MemberBinding binding, ReadOnlyCollection lambdaParameters) 
        { 
            switch (binding.BindingType)
            { 
                case MemberBindingType.Assignment:
                    MemberAssignment assignment = (MemberAssignment)binding;
                    return Expression.Bind(assignment.Member, Rewrite(assignment.Expression, lambdaParameters));
 
                case MemberBindingType.ListBinding:
                    MemberListBinding list = (MemberListBinding)binding; 
                    return Expression.ListBind( 
                        list.Member,
                        from li in list.Initializers 
                        select
                        Expression.ElementInit(
                        li.AddMethod,
                        from arg in li.Arguments select Rewrite(arg, lambdaParameters))); 

                case MemberBindingType.MemberBinding: 
                    MemberMemberBinding member = (MemberMemberBinding)binding; 
                    return Expression.MemberBind(
                        member.Member, 
                        from b in member.Bindings select Rewrite(b, lambdaParameters));

                default:
                    Fx.Assert("MemberBinding type '" + binding.BindingType + "' is not supported."); 
                    return binding;
            } 
        } 

        static ParameterExpression FindParameter(Expression expression) 
        {
            if (expression == null)
            {
                return null; 
            }
            switch (expression.NodeType) 
            { 
                case ExpressionType.Add:
                case ExpressionType.AddChecked: 
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                case ExpressionType.Coalesce:
                case ExpressionType.Divide: 
                case ExpressionType.Equal:
                case ExpressionType.ExclusiveOr: 
                case ExpressionType.GreaterThan: 
                case ExpressionType.GreaterThanOrEqual:
                case ExpressionType.LeftShift: 
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.Modulo:
                case ExpressionType.Multiply: 
                case ExpressionType.MultiplyChecked:
                case ExpressionType.NotEqual: 
                case ExpressionType.Or: 
                case ExpressionType.OrElse:
                case ExpressionType.Power: 
                case ExpressionType.RightShift:
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    BinaryExpression binaryExpression = (BinaryExpression)expression; 
                    return FindParameter(binaryExpression.Left) ?? FindParameter(binaryExpression.Right);
 
                case ExpressionType.Conditional: 
                    ConditionalExpression conditional = (ConditionalExpression)expression;
                    return FindParameter(conditional.Test) ?? FindParameter(conditional.IfTrue) ?? FindParameter(conditional.IfFalse); 

                case ExpressionType.Constant:
                    return null;
 
                case ExpressionType.Invoke:
                    InvocationExpression invocation = (InvocationExpression)expression; 
                    return FindParameter(invocation.Expression) ?? FindParameter(invocation.Arguments); 

                case ExpressionType.Lambda: 
                    LambdaExpression lambda = (LambdaExpression)expression;
                    return FindParameter(lambda.Body);

                case ExpressionType.ListInit: 
                    ListInitExpression listInit = (ListInitExpression)expression;
                    return FindParameter(listInit.NewExpression) ?? FindParameter(listInit.Initializers); 
 
                case ExpressionType.MemberAccess:
                    MemberExpression memberExpression = (MemberExpression)expression; 
                    return FindParameter(memberExpression.Expression);

                case ExpressionType.MemberInit:
                    MemberInitExpression memberInit = (MemberInitExpression)expression; 
                    return FindParameter(memberInit.NewExpression) ?? FindParameter(memberInit.Bindings);
 
                case ExpressionType.ArrayIndex: 
                    // ArrayIndex can be a MethodCallExpression or a BinaryExpression
                    MethodCallExpression arrayIndex = expression as MethodCallExpression; 
                    if (arrayIndex != null)
                    {
                        return FindParameter(arrayIndex.Object) ?? FindParameter(arrayIndex.Arguments);
                    } 
                    BinaryExpression alternateIndex = (BinaryExpression)expression;
                    return FindParameter(alternateIndex.Left) ?? FindParameter(alternateIndex.Right); 
 
                case ExpressionType.Call:
                    MethodCallExpression methodCall = (MethodCallExpression)expression; 
                    return FindParameter(methodCall.Object) ?? FindParameter(methodCall.Arguments);

                case ExpressionType.NewArrayInit:
                case ExpressionType.NewArrayBounds: 
                    NewArrayExpression newArray = (NewArrayExpression)expression;
                    return FindParameter(newArray.Expressions); 
 
                case ExpressionType.New:
                    NewExpression newExpression = (NewExpression)expression; 
                    return FindParameter(newExpression.Arguments);

                case ExpressionType.Parameter:
                    ParameterExpression parameterExpression = (ParameterExpression)expression; 
                    if (parameterExpression.Type == typeof(ActivityContext) && parameterExpression.Name == "context")
                    { 
                        return parameterExpression; 
                    }
                    return null; 

                case ExpressionType.TypeIs:
                    TypeBinaryExpression typeBinary = (TypeBinaryExpression)expression;
                    return FindParameter(typeBinary.Expression); 

                case ExpressionType.ArrayLength: 
                case ExpressionType.Convert: 
                case ExpressionType.ConvertChecked:
                case ExpressionType.Negate: 
                case ExpressionType.NegateChecked:
                case ExpressionType.Not:
                case ExpressionType.Quote:
                case ExpressionType.TypeAs: 
                case ExpressionType.UnaryPlus:
                    UnaryExpression unary = (UnaryExpression)expression; 
                    return FindParameter(unary.Operand); 

                // Expression Tree V2.0 types 

                case ExpressionType.Block:
                    BlockExpression block = (BlockExpression)expression;
                    ParameterExpression toReturn = FindParameter(block.Expressions); 
                    if (toReturn != null)
                    { 
                        return toReturn; 
                    }
                    List variableList = new List(); 
                    foreach (ParameterExpression variable in block.Variables)
                    {
                        variableList.Add(variable);
                    } 
                    return FindParameter(variableList);
 
                case ExpressionType.Assign: 
                    BinaryExpression assign = (BinaryExpression)expression;
                    return FindParameter(assign.Left) ?? FindParameter(assign.Right); 
            }

            Fx.Assert("Don't understand expression type " + expression.NodeType);
            return null; 
        }
 
        static ParameterExpression FindParameter(ICollection collection) 
        {
            foreach (Expression expression in collection) 
            {
                ParameterExpression result = FindParameter(expression);
                if (result != null)
                { 
                    return result;
                } 
            } 
            return null;
        } 

        static ParameterExpression FindParameter(ICollection collection)
        {
            foreach (ElementInit init in collection) 
            {
                ParameterExpression result = FindParameter(init.Arguments); 
                if (result != null) 
                {
                    return result; 
                }
            }
            return null;
        } 

        static ParameterExpression FindParameter(ICollection bindings) 
        { 
            foreach (MemberBinding binding in bindings)
            { 
                ParameterExpression result;
                switch (binding.BindingType)
                {
                    case MemberBindingType.Assignment: 
                        MemberAssignment assignment = (MemberAssignment)binding;
                        result = FindParameter(assignment.Expression); 
                        break; 

                    case MemberBindingType.ListBinding: 
                        MemberListBinding list = (MemberListBinding)binding;
                        result = FindParameter(list.Initializers);
                        break;
 
                    case MemberBindingType.MemberBinding:
                        MemberMemberBinding member = (MemberMemberBinding)binding; 
                        result = FindParameter(member.Bindings); 
                        break;
 
                    default:
                        Fx.Assert("MemberBinding type '" + binding.BindingType + "' is not supported.");
                        result = null;
                        break; 
                }
                if (result != null) 
                { 
                    return result;
                } 
            }
            return null;
        }
 
        static void EnsureTypeReferenced(Type type, ref HashSet typeReferences)
        { 
            // lookup cache 
            // underlying assumption is that type's inheritance(or interface) hierarchy
            // stays static throughout the lifetime of AppDomain 
            HashSet alreadyVisited = (HashSet)typeReferenceCache.GetValue(typeReferenceCacheLock, type);
            if (alreadyVisited != null)
            {
                if (typeReferences == null) 
                {
                    // used in VBHelper.Compile<> 
                    // must not alter this set being returned for integrity of cache 
                    typeReferences = alreadyVisited;
                } 
                else
                {
                    // used in VBDesignerHelper.FindTypeReferences
                    typeReferences.UnionWith(alreadyVisited); 
                }
                return; 
            } 

            alreadyVisited = new HashSet(); 
            EnsureTypeReferencedRecurse(type, alreadyVisited);

            // cache resulting alreadyVisited set for fast future lookup
            lock (typeReferenceCacheLock) 
            {
                typeReferenceCache.Add(type, alreadyVisited); 
            } 

            if (typeReferences == null) 
            {
                // used in VBHelper.Compile<>
                // must not alter this set being returned for integrity of cache
                typeReferences = alreadyVisited; 
            }
            else 
            { 
                // used in VBDesignerHelper.FindTypeReferences
                typeReferences.UnionWith(alreadyVisited); 
            }
            return;
        }
 
        static void EnsureTypeReferencedRecurse(Type type, HashSet alreadyVisited)
        { 
            if (alreadyVisited.Contains(type)) 
            {
                // this prevents circular reference 
                // example), class Foo : IBar
                return;
            }
 
            alreadyVisited.Add(type);
 
            // make sure any interfaces needed by this type are referenced 
            Type[] interfaces = type.GetInterfaces();
            for (int i = 0; i < interfaces.Length; ++i) 
            {
                EnsureTypeReferencedRecurse(interfaces[i], alreadyVisited);
            }
 
            // same for base types
            Type baseType = type.BaseType; 
            while ((baseType != null) && (baseType != TypeHelper.ObjectType)) 
            {
                EnsureTypeReferencedRecurse(baseType, alreadyVisited); 
                baseType = baseType.BaseType;
            }

            // for generic types, all type arguments 
            if (type.IsGenericType)
            { 
                Type[] typeArgs = type.GetGenericArguments(); 
                for (int i = 1; i < typeArgs.Length; ++i)
                { 
                    EnsureTypeReferencedRecurse(typeArgs[i], alreadyVisited);
                }
            }
 
            // array types
            if (type.HasElementType) 
            { 
                EnsureTypeReferencedRecurse(type.GetElementType(), alreadyVisited);
            } 

            return;
        }
 
        class VisualBasicImportScope : IImportScope
        { 
            IList importList; 

            public VisualBasicImportScope(IList importList) 
            {
                this.importList = importList;
            }
            public IList GetImports() 
            {
                return this.importList; 
            } 
        }
 
        class VisualBasicScriptAndTypeScope : IScriptScope, ITypeScope
        {
            LocationReferenceEnvironment environmentProvider;
            List assemblies; 
            string errorMessage;
 
            public VisualBasicScriptAndTypeScope(LocationReferenceEnvironment environmentProvider, List assemblies) 
            {
                this.environmentProvider = environmentProvider; 
                this.assemblies = assemblies;
            }

            public string ErrorMessage 
            {
                get { return this.errorMessage; } 
            } 

            public Type FindVariable(string name) 
            {
                LocationReference referenceToReturn = null;
                bool isFirstMatchAlreadyFound = false;
                bool isSecondMatchFound = false; 
                LocationReferenceEnvironment currentEnvironment = this.environmentProvider;
                while (currentEnvironment != null && !isSecondMatchFound) 
                { 
                    foreach (LocationReference reference in currentEnvironment.GetLocationReferences())
                    { 
                        if (string.Equals(reference.Name, name, StringComparison.OrdinalIgnoreCase))
                        {
                            if (isFirstMatchAlreadyFound)
                            { 
                                isSecondMatchFound = true;
                                break; 
                            } 
                            isFirstMatchAlreadyFound = true;
                            referenceToReturn = reference; 
                        }
                    }
                    currentEnvironment = currentEnvironment.Parent;
                } 

                if (isSecondMatchFound) 
                { 
                    // we have duplicate variable names across all visible environments!!!!
                    // compile error here!!!! 
                    this.errorMessage = SR.AmbiguousVBVariableReference(name);
                    return null;
                }
 
                if (isFirstMatchAlreadyFound)
                { 
                    Type referenceType = referenceToReturn.Type; 
                    HashSet allBaseTypes = null;
                    VisualBasicHelper.EnsureTypeReferenced(referenceType, ref allBaseTypes); 
                    foreach (Type baseType in allBaseTypes)
                    {
                        // allBaseTypes always contains referenceType
                        if (!this.assemblies.Contains(baseType.Assembly)) 
                        {
                            // if this.assemblies list doesn't contain all the assemblies 
                            // that define referenceType and its all base types, 
                            // then we gracefully fail compilation by pretending
                            // the identifier is unknown.  Otherwise the VB compiler may crash 
                            return null;
                        }
                    }
                    return referenceType; 
                }
 
                return null; 
            }
 
            public Type[] FindTypes(string typeName, string nsPrefix)
            {
                return null;
            } 

            public bool NamespaceExists(string ns) 
            { 
                return false;
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

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