예제 #1
0
        /// <summary>
        /// Collapses unnecessary double-branches into a single branch.
        /// </summary>
        /// <param name="node">Node that possibly begins a double-branch.</param>
        /// <returns>True if a double Branch was collapsed; false otherwise.</returns>
        private static bool CollapseDoubleBranches(BlockNode node)
        {
            // Sometimes a method body can have blocks like:
            // [ .... ]
            // [branch]
            //    |
            //    |
            //    |
            // [branch]
            //    |
            //    |
            //    |
            // [ .... ]
            //
            // We collapse these into:
            // [ .... ]
            // [branch]
            //    |
            //    |
            //    |
            // [ .... ]

            if (node.Outgoing.Count == 1)
            {
                BlockNode target = node.Graph[node.Outgoing[0].Target];
                if (target.Outgoing.Count == 1 &&
                    (target.Block.Statements.Count == 0 ||
                     target.Block.Statements.Count == 1 && target.Block.Statements[0] is Branch))
                {
                    RemoveStatements(node.Block.Statements, node.Outgoing[0]);
                    node.Block.Statements.Add(target.Outgoing[0]);
                    node.Refresh();

                    if (target.Incoming.Count == 0)
                    {
                        node.Graph.Remove(target);
                    }

                    return(true);
                }
            }
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Looks for normalized ternary expression patterns and creates TernaryExpressions.
        /// </summary>
        /// <param name="node">Node that possibly begins a normalized ternary expression.</param>
        /// <returns>True if a ternary expression was abnormalized; false otherwise.</returns>
        private static bool AbnormalizeExpression(BlockNode node)
        {
            // f(a ? b : c) is:             f(a && b) is:                f(a || b) is:
            // [     ...     ]              [      ...     ]             [     ...     ]
            // [if (a) branch]              [if (!a) branch]             [if (a) branch]
            //     / \                          / \                          / \
            //    /a  \fallthrough             /!a \fallthrough             /a  \fallthrough
            //   /     \                      /     \                      /     \
            // [b]     [c]                  [0]     [b]                  [1]     [b]
            //   \     /                      \     /                      \     /
            //    \   /                        \   /                        \   /
            //     \ /                          \ /                          \ /
            //  [f(pop)]                     [f(pop)]                     [f(pop)]
            //  [ .... ]                     [ .... ]                     [ .... ]

            BlockGraph graph = node.Graph;

            // First check the structure of head.
            if (node.Outgoing.Count == 2 &&
                node.Outgoing[0].Condition != null &&
                node.Outgoing[1].Condition == null &&
                node.Outgoing[0].Target != null &&
                node.Outgoing[1].Target != null)
            {
                // Then check the structure of the tails.
                BlockNode node0 = graph[node.Outgoing[0].Target];
                BlockNode node1 = graph[node.Outgoing[1].Target];
                if (node0.Outgoing.Count == 1 &&
                    node1.Outgoing.Count == 1 &&
                    node0.Outgoing[0].Target == node1.Outgoing[0].Target &&
                    node0.Block.Statements != null &&
                    node1.Block.Statements != null &&
                    node0.Block.Statements.Count > 0 &&
                    node1.Block.Statements.Count > 0 &&
                    (node0.Block.Statements.Count < 2 ||
                     node0.Block.Statements[1] is Branch) &&
                    (node1.Block.Statements.Count < 2 ||
                     node1.Block.Statements[1] is Branch))
                {
                    // The structure matches, so analyze the conditions.
                    Expression          condition       = node.Outgoing[0].Condition;
                    ExpressionStatement trueStatement   = node0.Block.Statements.Count > 0 ? node0.Block.Statements[0] as ExpressionStatement : null;
                    ExpressionStatement falseStatement  = node1.Block.Statements.Count > 0 ? node1.Block.Statements[0] as ExpressionStatement : null;
                    Expression          trueExpression  = trueStatement != null ? trueStatement.Expression : null;
                    Expression          falseExpression = falseStatement != null ? falseStatement.Expression : null;
                    if (trueExpression != null &&
                        trueExpression.Type != null &&
                        falseExpression != null &&
                        falseExpression.Type != null)
                    {
                        // Fix up the type information on boolean operators.
                        NodeType[] booleanNodeTypes =
                        {
                            NodeType.Ceq,
                            NodeType.Cgt,
                            NodeType.Clt,
                            NodeType.Cgt_Un,
                            NodeType.Clt_Un,
                            NodeType.Eq,
                            NodeType.Gt,
                            NodeType.Ge,
                            NodeType.Lt,
                            NodeType.Le,
                            NodeType.LogicalAnd,
                            NodeType.LogicalOr,
                            NodeType.LogicalEqual,
                            NodeType.LogicalImply,
                            NodeType.LogicalNot
                        };
                        if (Array.IndexOf(booleanNodeTypes, condition.NodeType) >= 0)
                        {
                            condition.Type = SystemTypes.Boolean;
                        }
                        if (Array.IndexOf(booleanNodeTypes, trueExpression.NodeType) >= 0)
                        {
                            trueExpression.Type = SystemTypes.Boolean;
                        }
                        if (Array.IndexOf(booleanNodeTypes, falseExpression.NodeType) >= 0)
                        {
                            falseExpression.Type = SystemTypes.Boolean;
                        }

                        // The expressions are valid, so see what kind of abnormal expression to create.
                        Expression abnormal = null;

                        // Check for short-circuit boolean binary expressions.
                        Literal literal = trueExpression as Literal;
                        if (literal != null && falseExpression.Type == SystemTypes.Boolean)
                        {
                            if (0.Equals(literal.Value)) // !trueExp && falseExp

                            {
                                abnormal = new BinaryExpression(
                                    Abnormalizer.LogicallyNegate(condition),
                                    falseExpression,
                                    NodeType.LogicalAnd,
                                    SystemTypes.Boolean,
                                    condition.SourceContext);
                            }
                            else if (1.Equals(literal.Value)) // trueExp || falseExp

                            {
                                abnormal = new BinaryExpression(
                                    condition,
                                    falseExpression,
                                    NodeType.LogicalOr,
                                    SystemTypes.Boolean,
                                    condition.SourceContext);
                            }
                        }

                        // Possibly merge it as part of an existing ternary expression.
                        if (abnormal == null)
                        {
                            TernaryExpression ternary = falseExpression as TernaryExpression;
                            if (ternary != null &&
                                ternary.NodeType == NodeType.Conditional)
                            {
                                if (trueExpression == ternary.Operand3)
                                {
                                    // It's a logical && embedded in a ternary expression.
                                    abnormal = new TernaryExpression(
                                        new BinaryExpression(
                                            Abnormalizer.LogicallyNegate(condition),
                                            ternary.Operand1,
                                            NodeType.LogicalAnd,
                                            SystemTypes.Boolean,
                                            condition.SourceContext),
                                        ternary.Operand2,
                                        ternary.Operand3,
                                        ternary.NodeType,
                                        ternary.Type);
                                }
                                else if (trueExpression == ternary.Operand2)
                                {
                                    // It's a logical || embedded in a ternary expression.
                                    abnormal = new TernaryExpression(
                                        new BinaryExpression(
                                            condition,
                                            ternary.Operand1,
                                            NodeType.LogicalOr,
                                            SystemTypes.Boolean,
                                            condition.SourceContext),
                                        ternary.Operand2,
                                        ternary.Operand3,
                                        ternary.NodeType,
                                        ternary.Type);
                                }
                            }
                        }

                        // If all else fails, treat it as a ternary expression.
                        if (abnormal == null)
                        {
                            // Infer the correct type of the expression.
                            TypeNode type = null;
                            if (Literal.IsNullLiteral(trueExpression))
                            {
                                type = falseExpression.Type;
                            }
                            else if (Literal.IsNullLiteral(falseExpression))
                            {
                                type = trueExpression.Type;
                            }
                            else if (trueExpression.Type.IsAssignableTo(falseExpression.Type))
                            {
                                type = falseExpression.Type;
                            }
                            else if (falseExpression.Type.IsAssignableTo(trueExpression.Type))
                            {
                                type = trueExpression.Type;
                            }
                            else // Instead of finding the greatest common denominator, just use object.
                            {
                                type = SystemTypes.Object;
                            }

                            abnormal = new TernaryExpression(
                                condition,
                                trueExpression,
                                falseExpression,
                                NodeType.Conditional,
                                type);
                        }

                        Debug.Assert(abnormal.Type != null, "We should never create an expression with a null type.");

                        // Try and get the best source context for the abnormal expression.
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = node.Outgoing[0].SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = condition.SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = trueExpression.SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = falseExpression.SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = trueStatement.SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = falseStatement.SourceContext;
                        }
                        if (abnormal.SourceContext.Document == null)
                        {
                            abnormal.SourceContext = node.Block.SourceContext;
                        }
                        // TODO: Keep looking more places for the elusive source context.

                        // Replace the branch with the abnormal expression and unconditional jump.
                        RemoveStatements(node.Block.Statements, node.Outgoing[0]);
                        node.Block.Statements.Add(new ExpressionStatement(abnormal, abnormal.SourceContext));
                        node.Block.Statements.Add(node0.Outgoing[0]);
                        node.Refresh();

                        // Remove the tail blocks if they are no longer used.
                        if (node0.Incoming.Count == 0)
                        {
                            graph.Remove(node0);
                        }
                        if (node1.Incoming.Count == 0)
                        {
                            graph.Remove(node1);
                        }

                        return(true);
                    }
                }
            }

            return(false);
        }