# HG changeset patch # User Paul Boddie # Date 1339357853 -7200 # Node ID 05abcd0316a58fd01062b33a618b9a196f25a00d # Parent 3815443bf7de8c20292907081de34c3bbf4ae704 Introduced separate handling of abandoned attribute usage branches so that exception handlers can restore usage from such branches. diff -r 3815443bf7de -r 05abcd0316a5 micropython/data.py --- a/micropython/data.py Sun Jun 10 18:38:37 2012 +0200 +++ b/micropython/data.py Sun Jun 10 21:50:53 2012 +0200 @@ -114,6 +114,10 @@ self.scope_usage = [{}] # stack of scope usage self.scope_shelves = [] + # Abandoned usage, useful for reviving usage for exception handlers. + + self.abandoned_users = [[]] # stack of lists of users + # Define attribute usage to identify active program sections. # Attribute users are AST nodes defining names. @@ -751,6 +755,10 @@ scope_usage.update(self.scope_usage[-1]) self.scope_usage.append(scope_usage) + # Retain a record of abandoned branch users. + + self.abandoned_users.append([]) + def _connect_users_to_branch(self, attribute_users, node): """ @@ -767,16 +775,21 @@ self._init_attribute_user(user) user._attrbranches.append(node) - def _abandon_branch(self): + def _abandon_branch(self, retain_branch=True): """ Abandon scope usage, permitting locally different scopes for names, provided these cannot "escape" from the branch. """ - self.attribute_users[-1] = abandoned_branch_users + attribute_users = self.attribute_users[-1] + + self.attribute_users[-1] = {} self.scope_usage[-1] = abandoned_branch_scope + if retain_branch: + self.abandoned_users[-1].append(attribute_users) + def _suspend_broken_branch(self): """ @@ -785,10 +798,9 @@ attribute_users = self.attribute_users[-1] - if not isinstance(attribute_users, AbandonedBranchUsers): - users = self.suspended_broken_users[-1] - users.append(attribute_users) - self._abandon_branch() + users = self.suspended_broken_users[-1] + users.append(attribute_users) + self._abandon_branch(False) def _suspend_continuing_branch(self): @@ -798,10 +810,9 @@ attribute_users = self.attribute_users[-1] - if not isinstance(attribute_users, AbandonedBranchUsers): - loop_node, users = self.suspended_continuing_users[-1] - users.append(attribute_users) - self._abandon_branch() + loop_node, users = self.suspended_continuing_users[-1] + users.append(attribute_users) + self._abandon_branch(False) def _shelve_branch(self): @@ -833,6 +844,12 @@ new_users = merge_mapping_dicts(all_shelved_users) self.attribute_users[-1] = new_users + # Abandoned users are retained for exception handling purposes. + + all_abandoned_users = self.abandoned_users.pop() + new_abandoned_users = merge_mapping_dicts(all_abandoned_users) + self.abandoned_users[-1].append(new_abandoned_users) + # Combine the scope usage. scope_usage = self.scope_usage[-1] @@ -919,6 +936,18 @@ new_users = merge_mapping_dicts(suspended_users + [current_users]) self.attribute_users[-1] = new_users + def _resume_abandoned_branches(self): + + """ + Incorporate users from abandoned branches into the current set of active + users. The abandoned branches are taken from the containing branch. + """ + + current_users = self.attribute_users[-1] + abandoned_users = self.abandoned_users[-2] + new_users = merge_mapping_dicts(abandoned_users + [current_users]) + self.attribute_users[-1] = new_users + # Scope usage methods. def define_scope(self, name, scope): @@ -979,15 +1008,6 @@ values = items = keys -class AbandonedBranchUsers(EmptyDict): - - """ - A class providing a value or state for an abandoned branch distinct from an - empty usage dictionary. - """ - - pass - class AbandonedBranchScope(EmptyDict): """ @@ -997,7 +1017,6 @@ pass -abandoned_branch_users = AbandonedBranchUsers() abandoned_branch_scope = AbandonedBranchScope() class ScopeConflict: diff -r 3815443bf7de -r 05abcd0316a5 micropython/inspect.py --- a/micropython/inspect.py Sun Jun 10 18:38:37 2012 +0200 +++ b/micropython/inspect.py Sun Jun 10 21:50:53 2012 +0200 @@ -410,6 +410,9 @@ def resume_continuing_branches(self): self.get_namespace()._resume_continuing_branches() + def resume_abandoned_branches(self): + self.get_namespace()._resume_abandoned_branches() + def define_attribute_user(self, node): """ @@ -1216,15 +1219,16 @@ return self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript") def visitTryExcept(self, node): + self.new_branchpoint() self.dispatch(node.body) - self.new_branchpoint() - - # NOTE: Attempt to recover abandoned branches from the body. - for name, var, n in node.handlers: self.new_branch(n) + # Any abandoned branches from the body can now be resumed. + + self.resume_abandoned_branches() + # Establish the local for the handler. if var is not None: @@ -1234,6 +1238,10 @@ self.shelve_branch() + # The else clause maintains the usage from the body but without the + # abandoned branches since they would never lead to the else clause + # being executed. + self.new_branch(node.else_ or NullBranch()) if node.else_ is not None: self.dispatch(node.else_)