internal override Variable AddVariable(string name, Type type, Expression valueAtTopOfScope)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            // If variables cannot be declared in the scope, try the parent scope instead.
            if (this.CanDeclareVariables == false)
            {
                if (this.ParentScope == null)
                {
                    throw new InvalidOperationException("Invalid scope chain.");
                }
                return(this.ParentScope.AddVariable(name, type, valueAtTopOfScope));
            }

            Variable variable;

            this.variables.TryGetValue(name, out variable);
            DeclaredVariable dVariable;

            if (variable == null || !(variable is DeclaredVariable))
            {
                // This is a local variable that has not been declared before (or is an arg being overwritten).
                dVariable = new DeclaredVariable()
                {
                    Name = name, Scope = this
                };
                variable             = dVariable;
                this.variables[name] = dVariable;
            }
            else
            {
                dVariable = (DeclaredVariable)variable;
            }

            // Set the initial value, if one was provided.
            if (valueAtTopOfScope != null)
            {
                // Function expressions override literals.
                if ((valueAtTopOfScope is LiteralExpression && dVariable.ValueAtTopOfScope is FunctionExpression) == false)
                {
                    dVariable.ValueAtTopOfScope = valueAtTopOfScope;
                }
            }

            variable.Type = type;
            return(variable);
        }
        /// <summary>Called before recompiling a function with different args.</summary>
        public override void Reset()
        {
            foreach (KeyValuePair <string, Variable> kvp in variables)
            {
                DeclaredVariable dec = kvp.Value as DeclaredVariable;

                if (dec == null)
                {
                    continue;
                }

                // Ensure store is cleared out:
                dec.Store = null;
            }
        }
        /// <summary>
        /// Generates code that initializes the variable and function declarations.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        internal void GenerateDeclarations(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Parent root:
            Expression rootExpression = optimizationInfo.RootExpression;

            // Initialize the declared variables and functions.
            foreach (var variable in this.variables.Values)
            {
                DeclaredVariable dVariable = variable as DeclaredVariable;

                // When a scope is reused, i.e. with an eval(), do not reinitialize the variables.
                if (dVariable == null || dVariable.Initialized)
                {
                    continue;
                }

                if (dVariable.ValueAtTopOfScope != null)
                {
                    // Emit the initialization code.

                    var name = new NameExpression(this, dVariable.Name);

                    Type rType = dVariable.ValueAtTopOfScope.GetResultType(optimizationInfo);

                    name.ApplyType(optimizationInfo, rType);

                    name.GenerateSet(generator, optimizationInfo, false, rType, delegate(bool two)
                    {
                        optimizationInfo.RootExpression = dVariable.ValueAtTopOfScope;

                        dVariable.ValueAtTopOfScope.GenerateCode(generator, optimizationInfo);

                        if (two)
                        {
                            // Dupe it:
                            generator.Duplicate();
                        }
                    }, false);

                    // Mark the variable as having been initialized.
                    dVariable.Initialized = true;
                }
            }

            // Restore root:
            optimizationInfo.RootExpression = rootExpression;
        }