internal LoopGotoTargets(string label, Block breakTarget, Block continueTarget)
 {
     this.Label = label;
     this.BreakTarget = breakTarget;
     this.ContinueTarget = continueTarget;
 }
        internal static void VisitDepthFirstOrder(Block block, List<Block> visitData)
        {
            if (ReferenceEquals(block._visitData, visitData))
                return;

            block._visitData = visitData;

            foreach (Block succ in block._successors)
            {
                VisitDepthFirstOrder(succ, visitData);
            }

            visitData.Add(block);
            block.PostOrder = count;
            count += 1;
        }
        /// <summary>
        /// Visit binary expression
        /// </summary>
        /// <param name="binaryExpressionAst"></param>
        /// <returns></returns>
        public object VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)
        {
            if (binaryExpressionAst == null) return null;

            if (binaryExpressionAst.Operator == TokenKind.And || binaryExpressionAst.Operator == TokenKind.Or)
            {
                // Logical and/or are short circuit operators, so we need to simulate the control flow.  The
                // left operand is always evaluated, visit it's expression in the current block.
                binaryExpressionAst.Left.Visit(this.Decorator);

                // The right operand is conditionally evaluated.  We aren't generating any code here, just
                // modeling the flow graph, so we just visit the right operand in a new block, and have
                // both the current and new blocks both flow to a post-expression block.
                var targetBlock = new Block();
                var nextBlock = new Block();
                _currentBlock.FlowsTo(targetBlock);
                _currentBlock.FlowsTo(nextBlock);
                _currentBlock = nextBlock;

                binaryExpressionAst.Right.Visit(this.Decorator);

                _currentBlock.FlowsTo(targetBlock);
                _currentBlock = targetBlock;
            }
            else
            {
                binaryExpressionAst.Left.Visit(this.Decorator);
                binaryExpressionAst.Right.Visit(this.Decorator);
            }

            return null;
        }
        /// <summary>
        /// Rename each variable (each assignment will give variable a new name).
        /// Also rename the phi function in each block as well
        /// </summary>
        /// <param name="block"></param>
        internal static void RenameVariables(Block block)
        {
            if (block._visited)
            {
                return;
            }

            block._visited = true;

            // foreach phi node generate new name
            foreach (var phi in block.Phis)
            {
                phi.Name = GenerateNewName(phi.RealName, block);
            }

            foreach (object ast in block._asts)
            {
                AssignmentTarget assignTarget = ast as AssignmentTarget;
                VariableTarget varTarget = null;

                if (assignTarget != null && !String.IsNullOrEmpty(assignTarget.Name))
                {
                    assignTarget.Name = GenerateNewName(assignTarget.Name, block);
                    varTarget = assignTarget._rightHandSideVariable;
                }

                varTarget = (varTarget != null) ? varTarget : ast as VariableTarget;

                if (varTarget != null)
                {
                    // If stack is empty then variable was not initialized;
                    if (SSADictionary[varTarget.RealName].Count == 0)
                    {
                        VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = new VariableAnalysisDetails { Name = varTarget.Name, DefinedBlock = null, Type = varTarget.Type, RealName = null };
                    }
                    else
                    {
                        VariableAnalysisDetails previous = SSADictionary[varTarget.RealName].Peek();
                        varTarget.Name = previous.Name;
                        if (previous.DefinedBlock != null)
                        {
                            previous.DefinedBlock.SSASuccessors.Add(block);
                        }

                        VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = previous;
                    }
                }
            }

            foreach (var successor in block._successors)
            {
                int index = successor._predecessors.IndexOf(block);
                foreach (var phi in successor.Phis)
                {
                    // Stacks may be empty when variable was not initialized on all paths;
                    if (SSADictionary[phi.RealName].Count != 0)
                    {
                        VariableAnalysisDetails previous = SSADictionary[phi.RealName].Peek();
                        if (previous.DefinedBlock != null)
                        {
                            previous.DefinedBlock.SSASuccessors.Add(successor);
                        }

                        phi.Operands[index] = new VariableTarget(previous);
                    }
                    else
                    {
                        phi.Operands[index] = new VariableTarget();
                        phi.Operands[index].Name = GenerateNewName(phi.RealName, null);
                    }
                }
            }

            // Preorder travel along the dominator tree
            foreach (var successor in block.DominatorSuccessors)
            {
                RenameVariables(successor);
            }

            foreach (var phi in block.Phis)
            {
                SSADictionary[phi.RealName].Pop();
            }

            foreach (object ast in block._asts)
            {
                AssignmentTarget assignTarget = ast as AssignmentTarget;
                if (assignTarget != null && !String.IsNullOrEmpty(assignTarget.RealName))
                {
                    SSADictionary[assignTarget.RealName].Pop();
                }
            }
        }
        /// <summary>
        /// Sparse simple constant algorithm using use-def chain from SSA graph.
        /// </summary>
        /// <param name="Variables"></param>
        /// <param name="Entry"></param>
        /// <param name="Classes"></param>
        /// <returns></returns>        
        #if PSV3

        internal static Tuple<Dictionary<string, VariableAnalysisDetails>, Dictionary<string, VariableAnalysisDetails>> SparseSimpleConstants(
             Dictionary<string, VariableAnalysisDetails> Variables, Block Entry)
        /// <summary>
        /// Fill in the DominanceFrontiersSet of each block.
        /// </summary>
        /// <param name="Blocks"></param>
        /// <param name="Entry"></param>
        internal static void DominanceFrontiers(List<Block> Blocks, Block Entry)
        {
            Block[] dominators = SetDominators(Entry, Blocks);

            foreach (Block block in Blocks)
            {
                if (block._predecessors.Count >= 2)
                {
                    foreach (Block pred in block._predecessors)
                    {
                        Block runner = pred;
                        while (runner != dominators[block.PostOrder])
                        {
                            runner.dominanceFrontierSet.Add(block);
                            runner = dominators[block.PostOrder];
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Given two nodes, return the postorder number of the closest node
        /// that dominates both.
        /// </summary>
        /// <param name="block1"></param>
        /// <param name="block2"></param>
        /// <param name="Dominators"></param>
        /// <returns></returns>
        internal static int Intersect(Block block1, Block block2, Block[] Dominators)
        {
            int b1 = block1.PostOrder;
            int b2 = block2.PostOrder;
            while (b1 != b2)
            {
                while (b1 < b2)
                {
                    b1 = Dominators[b1].PostOrder;
                }

                while (b2 < b1)
                {
                    b2 = Dominators[b2].PostOrder;
                }
            }

            return b1;
        }
        internal void GenerateWhileLoop(string loopLabel,
                                       Action generateCondition,
                                       Action generateLoopBody,
                                       Ast continueAction = null)
        {
            // We model the flow graph like this (if continueAction is null, the first part is slightly different):
            //    goto L
            //    :ContinueTarget
            //        continueAction
            //    :L
            //    if (condition)
            //    {
            //        loop body
            //        // break -> goto BreakTarget
            //        // continue -> goto ContinueTarget
            //        goto ContinueTarget
            //    }
            //    :BreakTarget

            var continueBlock = new Block();

            if (continueAction != null)
            {
                var blockAfterContinue = new Block();

                // Represent the goto over the condition before the first iteration.
                _currentBlock.FlowsTo(blockAfterContinue);

                _currentBlock = continueBlock;
                continueAction.Visit(this.Decorator);

                _currentBlock.FlowsTo(blockAfterContinue);
                _currentBlock = blockAfterContinue;
            }
            else
            {
                _currentBlock.FlowsTo(continueBlock);
                _currentBlock = continueBlock;
            }

            var bodyBlock = new Block();
            var breakBlock = new Block();

            // Condition can be null from an uncommon for loop: for() {}
            if (generateCondition != null)
            {
                generateCondition();
                _currentBlock.FlowsTo(breakBlock);
            }

            _loopTargets.Add(new LoopGotoTargets(loopLabel ?? "", breakBlock, continueBlock));
            _currentBlock.FlowsTo(bodyBlock);
            _currentBlock = bodyBlock;
            generateLoopBody();
            _currentBlock.FlowsTo(continueBlock);

            _currentBlock = breakBlock;

            _loopTargets.RemoveAt(_loopTargets.Count - 1);
        }
        internal void GenerateDoLoop(LoopStatementAst loopStatement)
        {
            // We model the flow graph like this:
            //    :RepeatTarget
            //       loop body
            //       // break -> goto BreakTarget
            //       // continue -> goto ContinueTarget
            //    :ContinueTarget
            //    if (condition)
            //    {
            //        goto RepeatTarget
            //    }
            //    :BreakTarget

            var continueBlock = new Block();
            var bodyBlock = new Block();
            var breakBlock = new Block();
            var gotoRepeatTargetBlock = new Block();

            _loopTargets.Add(new LoopGotoTargets(loopStatement.Label ?? "", breakBlock, continueBlock));

            _currentBlock.FlowsTo(bodyBlock);
            _currentBlock = bodyBlock;

            loopStatement.Body.Visit(this.Decorator);

            _currentBlock.FlowsTo(continueBlock);
            _currentBlock = continueBlock;

            loopStatement.Condition.Visit(this.Decorator);

            _currentBlock.FlowsTo(breakBlock);
            _currentBlock.FlowsTo(gotoRepeatTargetBlock);

            _currentBlock = gotoRepeatTargetBlock;
            _currentBlock.FlowsTo(bodyBlock);

            _currentBlock = breakBlock;

            _loopTargets.RemoveAt(_loopTargets.Count - 1);
        }
        /// <summary>
        /// Visit if statement
        /// </summary>
        /// <param name="ifStmtAst"></param>
        /// <returns></returns>
        public object VisitIfStatement(IfStatementAst ifStmtAst)
        {
            if (ifStmtAst == null) return null;

            Block afterStmt = new Block();

            if (ifStmtAst.ElseClause == null)
            {
                // There is no else, flow can go straight to afterStmt.
                _currentBlock.FlowsTo(afterStmt);
            }

            int clauseCount = ifStmtAst.Clauses.Count;
            for (int i = 0; i < clauseCount; i++)
            {
                var clause = ifStmtAst.Clauses[i];
                bool isLastClause = (i == (clauseCount - 1) && ifStmtAst.ElseClause == null);
                Block clauseBlock = new Block();
                Block nextBlock = isLastClause ? afterStmt : new Block();

                clause.Item1.Visit(this);

                _currentBlock.FlowsTo(clauseBlock);
                _currentBlock.FlowsTo(nextBlock);
                _currentBlock = clauseBlock;

                clause.Item2.Visit(this);

                _currentBlock.FlowsTo(afterStmt);
                _currentBlock = nextBlock;
            }

            if (ifStmtAst.ElseClause != null)
            {
                ifStmtAst.ElseClause.Visit(this);
                _currentBlock.FlowsTo(afterStmt);
            }

            _currentBlock = afterStmt;
            return null;
        }
        /// <summary>
        /// Visit switch statement
        /// </summary>
        /// <param name="switchStatementAst"></param>
        /// <returns></returns>
        public object VisitSwitchStatement(SwitchStatementAst switchStatementAst)
        {
            if (switchStatementAst == null) return null;

            Action generateCondition = () =>
            {
                switchStatementAst.Condition.Visit(this.Decorator);

                // $switch is set after evaluating the condition.
                _currentBlock.AddAst(new AssignmentTarget(SpecialVars.@switch, typeof(IEnumerator)));
            };

            Action switchBodyGenerator = () =>
            {
                bool hasDefault = (switchStatementAst.Default != null);
                Block afterStmt = new Block();

                int clauseCount = switchStatementAst.Clauses.Count;
                for (int i = 0; i < clauseCount; i++)
                {
                    var clause = switchStatementAst.Clauses[i];
                    Block clauseBlock = new Block();
                    bool isLastClause = (i == (clauseCount - 1) && !hasDefault);
                    Block nextBlock = isLastClause ? afterStmt : new Block();

                    clause.Item1.Visit(this.Decorator);

                    _currentBlock.FlowsTo(nextBlock);
                    _currentBlock.FlowsTo(clauseBlock);
                    _currentBlock = clauseBlock;

                    clause.Item2.Visit(this.Decorator);

                    if (!isLastClause)
                    {
                        _currentBlock.FlowsTo(nextBlock);
                        _currentBlock = nextBlock;
                    }
                }

                if (hasDefault)
                {
                    // If any clause was executed, we skip the default, so there is always a branch over the default.
                    _currentBlock.FlowsTo(afterStmt);
                    switchStatementAst.Default.Visit(this.Decorator);
                }

                _currentBlock.FlowsTo(afterStmt);
                _currentBlock = afterStmt;
            };

            GenerateWhileLoop(switchStatementAst.Label, generateCondition, switchBodyGenerator);

            return null;
        }
        /// <summary>
        /// Visit script block
        /// </summary>
        /// <param name="scriptBlockAst"></param>
        /// <returns></returns>
        public object VisitScriptBlock(ScriptBlockAst scriptBlockAst)
        {
            if (scriptBlockAst == null) return null;

            _currentBlock = _entryBlock;

            if (scriptBlockAst.DynamicParamBlock != null)
            {
                scriptBlockAst.DynamicParamBlock.Visit(this.Decorator);
            }

            if (scriptBlockAst.BeginBlock != null)
            {
                scriptBlockAst.BeginBlock.Visit(this.Decorator);
            }
            if (scriptBlockAst.ProcessBlock != null)
            {
                scriptBlockAst.ProcessBlock.Visit(this.Decorator);
            }
            if (scriptBlockAst.EndBlock != null)
            {
                scriptBlockAst.EndBlock.Visit(this.Decorator);
            }

            _currentBlock.FlowsTo(_exitBlock);

            return null;
        }
 /// <summary>
 /// Initialize the data flow construction
 /// </summary>
 public void Init()
 {
     _entryBlock = Block.NewEntryBlock();
     _exitBlock = new Block();
 }
 /// <summary>
 /// Start the data flow graph.
 /// </summary>
 public void Start()
 {
     Init();
     _currentBlock = _entryBlock;
 }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="VarName"></param>
        /// <param name="block"></param>
        internal Phi(String VarName, Block block)
        {
            Name = VarName;
            Operands = new VariableTarget[block._predecessors.Count()];
            for (int i = 0; i < Operands.Length; i += 1)
            {
                Operands[i] = new VariableTarget();
            }

            RealName = Name;
            DefinedBlock = block;
        }
        /// <summary>
        /// Visit foreach statement
        /// </summary>
        /// <param name="forEachStatementAst"></param>
        /// <returns></returns>
        public object VisitForEachStatement(ForEachStatementAst forEachStatementAst)
        {
            if (forEachStatementAst == null) return null;

            var afterFor = new Block();
            Action generateCondition = () =>
            {
                forEachStatementAst.Condition.Visit(this.Decorator);

                // The loop might not be executed, so add flow around the loop.
                _currentBlock.FlowsTo(afterFor);

                // $foreach and the iterator variable are set after evaluating the condition.
                _currentBlock.AddAst(new AssignmentTarget(SpecialVars.@foreach, typeof(IEnumerator)));
                _currentBlock.AddAst(new AssignmentTarget(forEachStatementAst.Variable));
            };

            GenerateWhileLoop(forEachStatementAst.Label, generateCondition, () => forEachStatementAst.Body.Visit(this.Decorator));

            _currentBlock.FlowsTo(afterFor);
            _currentBlock = afterFor;

            return null;
        }
 /// <summary>
 /// Tell flow analysis that this block can flow to next block.
 /// </summary>
 /// <param name="next"></param>
 internal void FlowsTo(Block next)
 {
     if (_successors.IndexOf(next) < 0)
     {
         if (!_unreachable)
         {
             next._unreachable = false;
         }
         _successors.Add(next);
         next._predecessors.Add(this);
     }
 }
        /// <summary>
        /// Visit try statement
        /// </summary>
        /// <param name="tryStatementAst"></param>
        /// <returns></returns>
        public object VisitTryStatement(TryStatementAst tryStatementAst)
        {
            if (tryStatementAst == null) return null;

            // We don't attempt to accurately model flow in a try catch because every statement
            // can flow to each catch.  Instead, we'll assume the try block is not executed (because the very first statement
            // may throw), and have the data flow assume the block before the try is all that can reach the catches and finally.

            var blockBeforeTry = _currentBlock;
            _currentBlock = new Block();
            blockBeforeTry.FlowsTo(_currentBlock);

            tryStatementAst.Body.Visit(this.Decorator);

            Block lastBlockInTry = _currentBlock;
            var finallyFirstBlock = tryStatementAst.Finally == null ? null : new Block();
            Block finallyLastBlock = null;

            // This is the first block after all the catches and finally (if present).
            var afterTry = new Block();

            bool isCatchAllPresent = false;

            foreach (var catchAst in tryStatementAst.CatchClauses)
            {
                if (catchAst.IsCatchAll)
                {
                    isCatchAllPresent = true;
                }

                // Any statement in the try block could throw and reach the catch, so assume the worst (from a data
                // flow perspective) and make the predecessor to the catch the block before entering the try.
                _currentBlock = new Block();
                blockBeforeTry.FlowsTo(_currentBlock);
                catchAst.Visit(this.Decorator);
                _currentBlock.FlowsTo(finallyFirstBlock ?? afterTry);
            }

            if (finallyFirstBlock != null)
            {
                lastBlockInTry.FlowsTo(finallyFirstBlock);

                _currentBlock = finallyFirstBlock;
                tryStatementAst.Finally.Visit(this.Decorator);
                _currentBlock.FlowsTo(afterTry);

                finallyLastBlock = _currentBlock;

                // For finally block, there are 2 cases: when try-body throw and when it doesn't.
                // For these two cases value of 'finallyLastBlock._throws' would be different.
                if (!isCatchAllPresent)
                {
                    // This flow exist only, if there is no catch for all exceptions.
                    blockBeforeTry.FlowsTo(finallyFirstBlock);

                    var rethrowAfterFinallyBlock = new Block();
                    finallyLastBlock.FlowsTo(rethrowAfterFinallyBlock);
                    rethrowAfterFinallyBlock._throws = true;
                    rethrowAfterFinallyBlock.FlowsTo(_exitBlock);
                }

                // This flow always exists.
                finallyLastBlock.FlowsTo(afterTry);
            }
            else
            {
                lastBlockInTry.FlowsTo(afterTry);
            }

            _currentBlock = afterTry;

            return null;
        }
        /// <summary>
        /// Returns the immediate dominator of each block. The array returned is
        /// indexed by postorder number of each block.
        /// Based on http://www.cs.rice.edu/~keith/Embed/dom.pdf
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="Blocks"></param>
        /// <returns></returns>
        internal static Block[] SetDominators(Block entry, List<Block> Blocks)
        {
            Block[] dominators = new Block[Blocks.Count];

            foreach (var block in Blocks)
            {
                dominators[block.PostOrder] = null;
            }

            dominators[entry.PostOrder] = entry;
            bool updated = true;

            while (updated)
            {
                updated = false;
                foreach (var block in Blocks)
                {
                    if (block == entry)
                    {
                        continue;
                    }

                    if (block._predecessors.Count == 0)
                    {
                        continue;
                    }

                    Block dom = block._predecessors[0];

                    // Get first processed node
                    foreach (var pred in block._predecessors)
                    {
                        if (dominators[pred.PostOrder] != null)
                        {
                            dom = pred;
                            break;
                        }
                    }

                    Block firstSelected = dom;

                    foreach (var pred in block._predecessors)
                    {
                        if (firstSelected != pred && dominators[pred.PostOrder] != null)
                        {
                            // The order is reversed so we have to subtract from total
                            dom = Blocks[Blocks.Count - Intersect(pred, dom, dominators) - 1];
                        }
                    }

                    if (dominators[block.PostOrder] != dom)
                    {
                        dominators[block.PostOrder] = dom;
                        updated = true;
                    }
                }
            }

            // Construct dominator tree
            foreach (var block in Blocks)
            {
                dominators[block.PostOrder].DominatorSuccessors.Add(block);
            }

            return dominators;
        }
        void BreakOrContinue(ExpressionAst label, Func<LoopGotoTargets, Block> fieldSelector)
        {
            Block targetBlock = null;
            if (label != null)
            {
                label.Visit(this.Decorator);
                if (_loopTargets.Any())
                {
                    var labelStrAst = label as StringConstantExpressionAst;
                    if (labelStrAst != null)
                    {
                        targetBlock = (from t in _loopTargets
                                       where t.Label.Equals(labelStrAst.Value, StringComparison.OrdinalIgnoreCase)
                                       select fieldSelector(t)).LastOrDefault();
                    }
                }
            }
            else if (_loopTargets.Count > 0)
            {
                targetBlock = fieldSelector(_loopTargets.Last());
            }

            if (targetBlock == null)
            {
                _currentBlock.FlowsTo(_exitBlock);
                _currentBlock._throws = true;
            }
            else
            {
                _currentBlock.FlowsTo(targetBlock);
            }

            // The next block is unreachable, but is necessary to keep the flow graph correct.
            _currentBlock = new Block();
        }
        /// <summary>
        /// Generate new name for each assignment using the counters.
        /// </summary>
        /// <param name="VarName"></param>
        /// <param name="DefinedBlock"></param>
        /// <returns></returns>
        internal static string GenerateNewName(string VarName, Block DefinedBlock)
        {
            int i = Counters[VarName];
            Counters[VarName] += 1;

            string newName = String.Format(CultureInfo.CurrentCulture, "{0}{1}", VarName, i);
            var varAnalysis = new VariableAnalysisDetails { Name = newName, DefinedBlock = DefinedBlock, RealName = VarName };

            SSADictionary[VarName].Push(varAnalysis);
            InternalVariablesDictionary[newName] = varAnalysis;

            return newName;
        }
        internal Block ControlFlowStatement(PipelineBaseAst pipelineAst)
        {
            if (pipelineAst != null)
            {
                pipelineAst.Visit(this.Decorator);
            }
            _currentBlock.FlowsTo(_exitBlock);
            var lastBlockInStatement = _currentBlock;

            // The next block is unreachable, but is necessary to keep the flow graph correct.
            _currentBlock = new Block();
            return lastBlockInStatement;
        }
        /// <summary>
        /// Initialize SSA
        /// </summary>
        /// <param name="VariableAnalysis"></param>
        /// <param name="Entry"></param>
        /// <param name="Blocks"></param>
        internal static void InitializeSSA(Dictionary<string, VariableAnalysisDetails> VariableAnalysis, Block Entry, List<Block> Blocks)
        {
            VariablesDictionary = new Dictionary<string, VariableAnalysisDetails>(StringComparer.OrdinalIgnoreCase);

            foreach (var block in Blocks)
            {
                List<Block> _unreachables = new List<Block>();
                foreach (var pred in block._predecessors)
                {
                    if (pred._unreachable)
                    {
                        _unreachables.Add(pred);
                        pred._successors.Remove(block);
                    }
                }

                foreach (var pred in _unreachables)
                {
                    block._predecessors.Remove(pred);
                }
            }

            InternalVariablesDictionary.Clear();
            SSADictionary.Clear();
            Counters.Clear();

            DominanceFrontiers(Blocks, Entry);

            InsertPhiNodes(VariableAnalysis);

            foreach (var key in VariableAnalysis.Keys.ToList())
            {
                SSADictionary[key] = new Stack<VariableAnalysisDetails>();
                Counters[key] = 0;
            }

            RenameVariables(Entry);
        }
        /// <summary>
        /// Visit pipeline
        /// </summary>
        /// <param name="pipelineAst"></param>
        /// <returns></returns>
        public object VisitPipeline(PipelineAst pipelineAst)
        {
            if (pipelineAst == null) return null;

            bool invokesCommand = false;
            foreach (var command in pipelineAst.PipelineElements)
            {
                command.Visit(this.Decorator);
                if (command is CommandAst)
                {
                    invokesCommand = true;
                }
                foreach (var redir in command.Redirections)
                {
                    redir.Visit(this.Decorator);
                }
            }

            // Because non-local gotos are supported, we must model them in the flow graph.  We can't detect them
            // in general, so we must be pessimistic and assume any command invocation could result in non-local
            // break or continue, so add the appropriate edges to our graph.  These edges occur after visiting
            // the command elements because command arguments could create new blocks, and we won't have executed
            // the command yet.
            if (invokesCommand && _loopTargets.Any())
            {
                foreach (var loopTarget in _loopTargets)
                {
                    _currentBlock.FlowsTo(loopTarget.BreakTarget);
                    _currentBlock.FlowsTo(loopTarget.ContinueTarget);
                }

                // The rest of the block is potentially unreachable, so split the current block.
                var newBlock = new Block();
                _currentBlock.FlowsTo(newBlock);
                _currentBlock = newBlock;
            }

            return null;
        }
            internal static Tuple<Dictionary<string, VariableAnalysisDetails>, Dictionary<string, VariableAnalysisDetails>> SparseSimpleConstants(
            Dictionary<string, VariableAnalysisDetails> Variables, Block Entry, List<TypeDefinitionAst> Classes)

        #endif
        {
            List<Block> blocks = GenerateReverseDepthFirstOrder(Entry);

            // Populate unreached variable with type from variables
            foreach (var block in blocks)
            {
                foreach (var ast in block._asts)
                {
                    VariableTarget varTarget = (ast is AssignmentTarget) ? (ast as AssignmentTarget)._rightHandSideVariable : (ast as VariableTarget);

                    if (varTarget != null && varTarget.Type == typeof(Unreached)
                        && Variables.ContainsKey(varTarget.Name))
                    {
                        varTarget.Type = Variables[varTarget.Name].Type;
                    }
                }
            }

            InitializeSSA(Variables, Entry, blocks);

            LinkedList<Tuple<Block, Block>> workLists = new LinkedList<Tuple<Block, Block>>();

            foreach (var block in blocks)
            {
                // Add a worklist from a block to itself to force analysis when variable is initialized but not used.
                // This is useful in the case where the variable is used in the inner function
                workLists.AddLast(Tuple.Create(block, block));

                foreach (var ssaSucc in block.SSASuccessors)
                {
                    if (ssaSucc != block)
                    {
                        workLists.AddLast(Tuple.Create(block, ssaSucc));
                    }
                }
            }

            // Initialize variables in internal dictionary to undetermined
            foreach (var key in InternalVariablesDictionary.Keys.ToList())
            {
                InternalVariablesDictionary[key].Constant = Undetermined.UndeterminedConstant;
                InternalVariablesDictionary[key].Type = typeof(Undetermined);
            }

            // Initialize DefinedBlock of phi function. If it is null then that phi function is not initialized;
            foreach (var block in blocks)
            {
                foreach (var phi in block.Phis)
                {
                    foreach (var operand in phi.Operands)
                    {
                        phi.DefinedBlock = operand.DefinedBlock;
                        if (phi.DefinedBlock == null)
                        {
                            break;
                        }
                    }

                    InternalVariablesDictionary[phi.Name].DefinedBlock = phi.DefinedBlock;
                }
            }

            while (workLists.Count != 0)
            {
                Tuple<Block, Block> SSAEdge = workLists.Last.Value;
                workLists.RemoveLast();
                Block start = SSAEdge.Item1;
                Block end = SSAEdge.Item2;

                HashSet<string> defVariables = new HashSet<string>();

                foreach (var obj in start._asts)
                {
                    var assigned = obj as AssignmentTarget;
                    if (assigned != null && assigned.Name != null && InternalVariablesDictionary.ContainsKey(assigned.Name))
                    {
                        VariableAnalysisDetails varAnalysis = InternalVariablesDictionary[assigned.Name];
                        // For cases where the type or constant of the rhs is initialized not through assignment.
                        if (assigned._rightHandSideVariable != null && !InternalVariablesDictionary.ContainsKey(assigned._rightHandSideVariable.Name)
                            && Variables.ContainsKey(assigned._rightHandSideVariable.Name))
                        {
                            VariableAnalysisDetails rhsAnalysis = Variables[assigned._rightHandSideVariable.Name];
                            assigned.Type = rhsAnalysis.Type;
                            assigned.Constant = rhsAnalysis.Constant;
                        }

                        varAnalysis.Constant = assigned.Constant;
                        varAnalysis.Type = assigned.Type;
                        defVariables.Add(assigned.Name);
                    }
                }

                foreach (var phi in start.Phis)
                {
                    EvaluatePhiConstant(phi);
                    EvaluatePhiType(phi);
                    defVariables.Add(phi.Name);
                }

                bool updated = false;

                List<VariableTarget> varTargets = new List<VariableTarget>();
                varTargets.AddRange(end._asts.Where(item => item is VariableTarget).Cast<VariableTarget>());

                foreach (var phi in end.Phis)
                {
                    varTargets.AddRange(phi.Operands);
                }

                foreach (var varTarget in varTargets)
                {
                    if (defVariables.Contains(varTarget.Name))
                    {
                        var analysisDetails = InternalVariablesDictionary[varTarget.Name];

                        if (!VariableDetails.SameConstantAndType(varTarget, analysisDetails))
                        {
                            updated = true;
                        }

                        varTarget.Constant = analysisDetails.Constant;
                        varTarget.Type = analysisDetails.Type;

                        VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = InternalVariablesDictionary[varTarget.Name];
                    }
                }

                foreach (var ast in end._asts)
                {
                    var assigned = ast as AssignmentTarget;
                    if (assigned != null && assigned.Name != null && assigned._leftHandSideVariable != null)
                    {
                        // Handle cases like $b = $a after we found out the value of $a
                        if (assigned._rightHandSideVariable != null
                            && defVariables.Contains(assigned._rightHandSideVariable.Name))
                        {
                            // Ignore assignments like $a = $a
                            if (!String.Equals(assigned._rightHandSideVariable.Name, assigned.Name, StringComparison.OrdinalIgnoreCase))
                            {
                                if (!InternalVariablesDictionary.ContainsKey(assigned._rightHandSideVariable.Name))
                                {
                                    continue;
                                }

                                var analysisDetails = InternalVariablesDictionary[assigned._rightHandSideVariable.Name];

                                if (!VariableDetails.SameConstantAndType(assigned, analysisDetails))
                                {
                                    updated = true;
                                }

                                assigned.Constant = analysisDetails.Constant;
                                assigned.Type = analysisDetails.Type;
                            }

                            continue;
                        }

                        //TODO
                        // Handle cases like $b = $a.SomeMethod or $a.SomeType after we found out the value of $a

                        if (assigned._rightAst != null)
                        {
                            CommandExpressionAst cmeAst = assigned._rightAst as CommandExpressionAst;
                            MemberExpressionAst memAst = (cmeAst != null) ? (cmeAst.Expression as MemberExpressionAst) : null;
                            // Don't handle the this case because this is handled in assignment target

                            if (memAst != null && memAst.Expression is VariableExpressionAst)
                            {
                                VariableAnalysisDetails analysis = VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(memAst.Expression as VariableExpressionAst)];

                                #if PSV3

                                Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis);

                                #else

                                TypeDefinitionAst psClass = Classes.FirstOrDefault(item => String.Equals(item.Name, analysis.Type.FullName, StringComparison.OrdinalIgnoreCase));
                                Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis, psClass);

                                #endif

                                if (possibleType != null && possibleType != assigned.Type)
                                {
                                    assigned.Type = possibleType;
                                    updated = true;
                                    continue;
                                }
                            }
                        }
                    }
                }

                if (updated)
                {
                    foreach (var block in end.SSASuccessors)
                    {
                        // Add to the front instead of the end since we are removing from end.
                        workLists.AddFirst(Tuple.Create(end, block));
                    }
                }
            }

            return Tuple.Create(VariablesDictionary, InternalVariablesDictionary);
        }
        internal static List<Block> GenerateReverseDepthFirstOrder(Block block)
        {
            count = 0;
            List<Block> result = new List<Block>();

            VisitDepthFirstOrder(block, result);
            result.Reverse();

            for (int i = 0; i < result.Count; i++)
            {
                result[i]._visitData = null;
            }

            return result;
        }