def computeExpressionRaw(self, constraint_collection): # The tried block must be considered as a branch, if it is not empty # already. tried_statement_sequence = self.getBlockTry() # May be "None" from the outset, so guard against that, later in this # function we are going to remove it. if tried_statement_sequence is not None: result = tried_statement_sequence.computeStatementsSequence( constraint_collection = constraint_collection ) # Might be changed. if result is not tried_statement_sequence: self.setBlockTry(result) tried_statement_sequence = result # The main expression itself. constraint_collection.onExpression(self.getExpression()) final_statement_sequence = self.getBlockFinal() # TODO: The final must not assume that all of tried was executed, # instead it may have aborted after any part of it, which is a rather # complex definition. if final_statement_sequence is not None: collection_exception_handling = ConstraintCollectionBranch( parent = constraint_collection, ) if tried_statement_sequence is not None: # Mark all variables as unknown that are written in the tried # block, so it destroys the assumptions for loop turn around. collection_exception_handling.degradePartiallyFromCode(tried_statement_sequence) # In case there are assignments hidden in the expression too. collection_exception_handling.degradePartiallyFromCode(self.getExpression()) # Then assuming no exception, the no raise block if present. result = final_statement_sequence.computeStatementsSequence( constraint_collection = collection_exception_handling ) if result is not final_statement_sequence: self.setBlockFinal(result) final_statement_sequence = result if tried_statement_sequence is None and \ final_statement_sequence is None: # If the tried and final block is empty, go to the expression # directly. return self.getExpression(), "new_expression", """\ Removed try/finally expression with empty tried and final block.""" else: if final_statement_sequence is not None: # Otherwise keep it as it, merging the finally block back into # the constraint collection. constraint_collection.mergeBranches( collection_yes = collection_exception_handling, collection_no = None ) # Otherwise keep it as it. return self, None, None
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.""" collection_exception_handling = ConstraintCollectionBranch( parent = constraint_collection, ) collection_exception_handling.degradePartiallyFromCode(tried_statement_sequence) if self.getExceptionHandling() is not None: collection_exception_handling.computeBranch( branch = self.getExceptionHandling() ) # Merge only, if the exception handling itself does exit. if self.getExceptionHandling() is None or \ not self.getExceptionHandling().isStatementAborting(): constraint_collection.mergeBranches( collection_yes = collection_exception_handling, collection_no = None ) # 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 remaining 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.""" new_statements = tried_statement_sequence.getStatements() # Determine statements inside the exception guard, that need not be in # a handler, because they wouldn't raise an exception. TODO: This # actual exception being watched for should be considered, by look # for any now. outside_pre = [] while new_statements and \ not new_statements[0].mayRaiseException(BaseException): outside_pre.append(new_statements[0]) new_statements = list(new_statements)[1:] outside_post = [] if self.getExceptionHandling() is not None and \ self.getExceptionHandling().isStatementAborting(): while new_statements and \ not new_statements[-1].mayRaiseException(BaseException): outside_post.insert(0, new_statements[-1]) new_statements = list(new_statements)[:-1] if outside_pre or outside_post: tried_statement_sequence.setStatements(new_statements) from .NodeMakingHelpers import makeStatementsSequenceReplacementNode result = makeStatementsSequenceReplacementNode( statements = outside_pre + [self] + outside_post, node = self ) return result, "new_statements", """\ Moved statements of tried block that cannot raise.""" return self, None, None
def computeStatement(self, constraint_collection): # The tried block must be considered as a branch, if it is not empty # already. tried_statement_sequence = self.getBlockTry() # May be "None" from the outset, so guard against that, later in this # function we are going to remove it. if tried_statement_sequence is not None: result = tried_statement_sequence.computeStatementsSequence( constraint_collection = constraint_collection ) # Might be changed. if result is not tried_statement_sequence: self.setBlockTry(result) tried_statement_sequence = result final_statement_sequence = self.getBlockFinal() if final_statement_sequence is not None: # TODO: The must not assume that all of tried was executed, instead # it may have aborted after any part of it, which is a rather # a complex situation, so we just invalidate all writes. collection_exception_handling = ConstraintCollectionBranch( parent = constraint_collection, ) if tried_statement_sequence is not None: collection_exception_handling.degradePartiallyFromCode(tried_statement_sequence) # Then assuming no exception, the no raise block if present. result = final_statement_sequence.computeStatementsSequence( constraint_collection = collection_exception_handling ) if result is not final_statement_sequence: self.setBlockFinal(result) final_statement_sequence = result # If we are not aborting, we need to merge. if not self.isStatementAborting(): # Merge back as a branch. constraint_collection.mergeBranches( collection_yes = collection_exception_handling, collection_no = None ) if tried_statement_sequence is None: # If the tried block is empty, go to the final block directly, if # any. return final_statement_sequence, "new_statements", """\ Removed try/finally with empty tried block.""" elif final_statement_sequence is None: # If the final block is empty, just need to execute the tried block # then. return tried_statement_sequence, "new_statements", """\ Removed try/finally with empty final block.""" elif not tried_statement_sequence.mayRaiseExceptionOrAbort( BaseException ): # There may be no need to try/finally at all then. TODO: The code # below, which reduces the scope, could do this too, but would be # less elegant in its report. tried_statement_sequence.setChild( "statements", tried_statement_sequence.getStatements() + final_statement_sequence.getStatements() ) return tried_statement_sequence, "new_statements", """\ Removed try/finally with try block that cannot raise.""" else: new_statements = tried_statement_sequence.getStatements() # Determine statements inside the exception guard, that need not be in # a handler, because they wouldn't raise an exception. TODO: This # actual exception being watched for should be considered, by look # for any now. outside_pre = [] while new_statements and \ not new_statements[0].mayRaiseException(BaseException) and \ not new_statements[0].mayReturn() and \ not new_statements[0].mayBreak() and \ not new_statements[0].mayContinue(): outside_pre.append(new_statements[0]) new_statements = list(new_statements)[1:] if outside_pre: tried_statement_sequence.setStatements(new_statements) from .NodeMakingHelpers import makeStatementsSequenceReplacementNode result = makeStatementsSequenceReplacementNode( statements = outside_pre + [self], node = self ) return result, "new_statements", """\ Moved statements of tried block that cannot abort to the outside.""" return self, None, None
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.""", ) collection_exception_handling = ConstraintCollectionBranch(parent=constraint_collection) collection_exception_handling.degradePartiallyFromCode(tried_statement_sequence) if self.getExceptionHandling() is not None: collection_exception_handling.computeBranch(branch=self.getExceptionHandling()) # Merge only, if the exception handling itself does exit. if self.getExceptionHandling() is None or not self.getExceptionHandling().isStatementAborting(): constraint_collection.mergeBranches(collection_yes=collection_exception_handling, collection_no=None) # 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 remaining 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.""", ) new_statements = tried_statement_sequence.getStatements() # Determine statements inside the exception guard, that need not be in # a handler, because they wouldn't raise an exception. TODO: This # actual exception being watched for should be considered, by look # for any now. outside_pre = [] while new_statements and not new_statements[0].mayRaiseException(BaseException): outside_pre.append(new_statements[0]) new_statements = list(new_statements)[1:] outside_post = [] if self.getExceptionHandling() is not None and self.getExceptionHandling().isStatementAborting(): while new_statements and not new_statements[-1].mayRaiseException(BaseException): outside_post.insert(0, new_statements[-1]) new_statements = list(new_statements)[:-1] if outside_pre or outside_post: tried_statement_sequence.setStatements(new_statements) from .NodeMakingHelpers import makeStatementsSequenceReplacementNode result = makeStatementsSequenceReplacementNode(statements=outside_pre + [self] + outside_post, node=self) return ( result, "new_statements", """\ Moved statements of tried block that cannot raise.""", ) return self, None, None