예제 #1
0
파일: TryNodes.py 프로젝트: wewela/Nuitka
    def computeStatement(self, constraint_collection):
        # The tried block can be processed normally.
        tried_statement_sequence = self.getBlockTry()

        # May be "None" from the outset, so guard against that, later we are
        # going to remove it.
        if tried_statement_sequence is not None:
            result = tried_statement_sequence.computeStatementsSequence(
                constraint_collection = constraint_collection
            )

            if result is not tried_statement_sequence:
                self.setBlockTry(result)

                tried_statement_sequence = result

        if tried_statement_sequence is None:
            return None, "new_statements", """\
Removed try/except with empty tried block."""

        # TODO: Need not to remove all knowledge, but only the parts that were
        # touched.
        constraint_collection.removeAllKnowledge()

        if self.getExceptionHandling() is not None:
            from nuitka.optimizations.ConstraintCollections import \
              ConstraintCollectionBranch
            collection_exception_handling = ConstraintCollectionBranch(
                parent = constraint_collection,
                branch = self.getExceptionHandling()
            )

        # Without exception handlers remaining, nothing else to do. They may
        # e.g. be removed as only re-raising.
        if self.getExceptionHandling() and \
           self.getExceptionHandling().getStatements()[0].\
             isStatementReraiseException():
            return tried_statement_sequence, "new_statements", """\
Removed try/except without any remaing handlers."""

        # Remove exception handling, if it cannot happen.
        if not tried_statement_sequence.mayRaiseException(BaseException):
            return tried_statement_sequence, "new_statements", """\
Removed try/except with tried block that cannot raise."""

        # Give up, merging this is too hard for now, any amount of the tried
        # sequence may have executed together with one of the handlers, or all
        # of tried and no handlers. TODO: improve this to an actual merge, even
        # if a pessimistic one.
        constraint_collection.removeAllKnowledge()

        return self, None, None
예제 #2
0
    def computeExpressionRaw(self, constraint_collection):
        # Children can tell all we need to know, pylint: disable=W0613

        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        constraint_collection.onExpression(expression=self.getCondition())
        condition = self.getCondition()

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            return condition, "new_raise", """\
Conditional statements already raises implicitely in condition, removing \
branches."""

        # If the condition raises, we let that escape.
        if condition.willRaiseException(BaseException):
            return condition, "new_raise", """\
Conditional expression raises in condition."""

        from nuitka.optimizations.ConstraintCollections import \
            ConstraintCollectionBranch

        # Decide this based on truth value of condition.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch should know that.
        yes_branch = self.getExpressionYes()

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if truth_value is not False:
            branch_yes_collection = ConstraintCollectionBranch(
                parent=constraint_collection, branch=yes_branch)

            # May have just gone away, so fetch it again.
            yes_branch = self.getExpressionYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch.willRaiseException(BaseException):
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        no_branch = self.getExpressionNo()

        # Continue to execute for yes branch.
        if truth_value is not True:
            branch_no_collection = ConstraintCollectionBranch(
                parent=constraint_collection, branch=no_branch)

            # May have just gone away, so fetch it again.
            no_branch = self.getExpressionNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch.willRaiseException(BaseException):
                branch_no_collection = None
        else:
            branch_no_collection = None

        # Merge into parent execution.
        constraint_collection.mergeBranches(branch_yes_collection,
                                            branch_no_collection)

        if truth_value is True:
            from .NodeMakingHelpers import wrapExpressionWithNodeSideEffects

            return (wrapExpressionWithNodeSideEffects(
                new_node=self.getExpressionYes(),
                old_node=condition), "new_expression",
                    "Conditional expression predicted to yes case")
        elif truth_value is False:
            from .NodeMakingHelpers import wrapExpressionWithNodeSideEffects

            return (wrapExpressionWithNodeSideEffects(
                new_node=self.getExpressionNo(),
                old_node=condition), "new_expression",
                    "Conditional expression predicted to no case")
        else:
            return self, None, None
예제 #3
0
    def computeStatement( self, constraint_collection ):
        # This is rather complex stuff, pylint: disable=R0912

        # Query the truth value before the expression is evaluated, once it is evaluated
        # in onExpression, it may change.
        condition = self.getCondition()
        truth_value = condition.getTruthValue()

        constraint_collection.onExpression( condition )
        condition = self.getCondition()

        from nuitka.optimizations.ConstraintCollections import ConstraintCollectionBranch

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch

        yes_branch = self.getBranchYes()

        if yes_branch is not None:
            branch_yes_collection = ConstraintCollectionBranch( constraint_collection )

            branch_yes_collection.process( yes_branch )

            # May have just gone away.
            yes_branch = self.getBranchYes()
        else:
            branch_yes_collection = None

        no_branch = self.getBranchNo()

        if no_branch is not None:
            branch_no_collection = ConstraintCollectionBranch( constraint_collection )

            branch_no_collection.process( no_branch )

            # May have just gone away.
            no_branch = self.getBranchNo()
        else:
            branch_no_collection = None


        # Merge into parent constraint collection.
        constraint_collection.mergeBranches( branch_yes_collection, branch_no_collection )

        if yes_branch is not None and no_branch is not None:
            # TODO: Merging should be done by method.
            constraint_collection.variables = constraint_collection.mergeBranchVariables(
                branch_yes_collection.variables,
                branch_no_collection.variables
            )
        elif yes_branch is not None:
            constraint_collection.mergeBranch( branch_yes_collection )
        elif no_branch is not None:
            constraint_collection.mergeBranch( branch_no_collection )
        else:
            from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode

            # With both branches eliminated, the condition remains as a side effect.
            result = makeStatementExpressionOnlyReplacementNode(
                expression = condition,
                node       = self
            )

            return result, "new_statements", """\
Both branches have no effect, reduced to evaluate condition."""

        if yes_branch is None:
            # Would be eliminated already, if there wasn't any "no" branch either.
            assert no_branch is not None

            from .OperatorNodes import ExpressionOperationNOT

            new_statement = StatementConditional(
                condition = ExpressionOperationNOT(
                    operand    = condition,
                    source_ref = condition.getSourceReference()
                ),
                yes_branch = no_branch,
                no_branch  = None,
                source_ref = self.getSourceReference()
            )

            return new_statement, "new_statements", """\
Empty 'yes' branch for condition was replaced with inverted condition check."""

        # Note: Checking the condition late, so that the surviving branches got processed
        # already. Returning without doing that, will lead to errorneous assumptions.
        if truth_value is not None:
            from .NodeMakingHelpers import wrapStatementWithSideEffects

            if truth_value is True:
                choice = "true"

                new_statement = self.getBranchYes()
            else:
                choice = "false"

                new_statement = self.getBranchNo()

            new_statement = wrapStatementWithSideEffects(
                new_node   = new_statement,
                old_node   = condition,
                allow_none = True # surviving branch may empty
            )

            return new_statement, "new_statements", """\
Condition for branch was predicted to be always %s.""" % choice
        elif condition.willRaiseException( BaseException ):
            from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode

            result = makeStatementExpressionOnlyReplacementNode(
                expression = condition,
                node       = self
            )

            return result, "new_raise", """\
Conditional statements already raises implicitely in condition, removing branches"""

        return self, None, None
예제 #4
0
    def computeStatement(self, constraint_collection):
        # This is rather complex stuff, pylint: disable=R0912

        # Query the truth value after the expression is evaluated, once it is
        # evaluated in onExpression, it is known.
        constraint_collection.onExpression(expression=self.getCondition())
        condition = self.getCondition()

        # No need to look any further, if the condition raises, the branches do
        # not matter at all.
        if condition.willRaiseException(BaseException):
            from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode

            result = makeStatementExpressionOnlyReplacementNode(
                expression=condition, node=self)

            return result, "new_raise", """\
Conditional statements already raises implicitely in condition, removing \
branches."""

        from nuitka.optimizations.ConstraintCollections import \
            ConstraintCollectionBranch

        # Consider to not execute branches that we know to be true, but execute
        # the ones that may be true, potentially both.
        truth_value = condition.getTruthValue()

        # TODO: We now know that condition evaluates to true for the yes branch
        # and to not true for no branch, the branch should know that.
        yes_branch = self.getBranchYes()

        # Handle branches that became empty behind our back
        if yes_branch is not None:
            if not yes_branch.getStatements():
                yes_branch = None

        # Continue to execute for yes branch unless we know it's not going to be
        # relevant.
        if yes_branch is not None and truth_value is not False:
            branch_yes_collection = ConstraintCollectionBranch(
                parent=constraint_collection, branch=yes_branch)

            # May have just gone away, so fetch it again.
            yes_branch = self.getBranchYes()

            # If it's aborting, it doesn't contribute to merging.
            if yes_branch is None or yes_branch.isStatementAborting():
                branch_yes_collection = None
        else:
            branch_yes_collection = None

        no_branch = self.getBranchNo()

        # Handle branches that became empty behind our back
        if no_branch is not None:
            if not no_branch.getStatements():
                no_branch = None

        # Continue to execute for yes branch.
        if no_branch is not None and truth_value is not True:
            branch_no_collection = ConstraintCollectionBranch(
                parent=constraint_collection, branch=no_branch)

            # May have just gone away, so fetch it again.
            no_branch = self.getBranchNo()

            # If it's aborting, it doesn't contribute to merging.
            if no_branch is None or no_branch.isStatementAborting():
                branch_no_collection = None
        else:
            branch_no_collection = None

        # Merge into parent execution.
        constraint_collection.mergeBranches(branch_yes_collection,
                                            branch_no_collection)

        # Both branches may have become empty.
        if yes_branch is None and no_branch is None:
            from .NodeMakingHelpers import \
                makeStatementExpressionOnlyReplacementNode

            # With both branches eliminated, the condition remains as a side
            # effect.
            result = makeStatementExpressionOnlyReplacementNode(
                expression=condition, node=self)

            return result, "new_statements", """\
Both branches have no effect, reduced to evaluate condition."""

        if yes_branch is None:
            # Would be eliminated already, if there wasn't any "no" branch
            # either.
            assert no_branch is not None

            from .OperatorNodes import ExpressionOperationNOT

            new_statement = StatementConditional(
                condition=ExpressionOperationNOT(
                    operand=condition,
                    source_ref=condition.getSourceReference()),
                yes_branch=no_branch,
                no_branch=None,
                source_ref=self.getSourceReference())

            return new_statement, "new_statements", """\
Empty 'yes' branch for condition was replaced with inverted condition check."""

        # Note: Checking the condition late, so that the surviving branch got
        # processed already. Returning without doing that, will corrupt the SSA
        # results. TODO: Could pretend the other branch didn't exist to save
        # complexity the merging of processing.
        if truth_value is not None:
            from .NodeMakingHelpers import wrapStatementWithSideEffects

            if truth_value is True:
                choice = "true"

                new_statement = self.getBranchYes()
            else:
                choice = "false"

                new_statement = self.getBranchNo()

            new_statement = wrapStatementWithSideEffects(
                new_node=new_statement,
                old_node=condition,
                allow_none=True  # surviving branch may empty
            )

            return new_statement, "new_statements", """\
Condition for branch was predicted to be always %s.""" % choice

        return self, None, None