1.1 --- a/micropython/data.py Sun Jun 10 18:38:37 2012 +0200
1.2 +++ b/micropython/data.py Sun Jun 10 21:50:53 2012 +0200
1.3 @@ -114,6 +114,10 @@
1.4 self.scope_usage = [{}] # stack of scope usage
1.5 self.scope_shelves = []
1.6
1.7 + # Abandoned usage, useful for reviving usage for exception handlers.
1.8 +
1.9 + self.abandoned_users = [[]] # stack of lists of users
1.10 +
1.11 # Define attribute usage to identify active program sections.
1.12 # Attribute users are AST nodes defining names.
1.13
1.14 @@ -751,6 +755,10 @@
1.15 scope_usage.update(self.scope_usage[-1])
1.16 self.scope_usage.append(scope_usage)
1.17
1.18 + # Retain a record of abandoned branch users.
1.19 +
1.20 + self.abandoned_users.append([])
1.21 +
1.22 def _connect_users_to_branch(self, attribute_users, node):
1.23
1.24 """
1.25 @@ -767,16 +775,21 @@
1.26 self._init_attribute_user(user)
1.27 user._attrbranches.append(node)
1.28
1.29 - def _abandon_branch(self):
1.30 + def _abandon_branch(self, retain_branch=True):
1.31
1.32 """
1.33 Abandon scope usage, permitting locally different scopes for names,
1.34 provided these cannot "escape" from the branch.
1.35 """
1.36
1.37 - self.attribute_users[-1] = abandoned_branch_users
1.38 + attribute_users = self.attribute_users[-1]
1.39 +
1.40 + self.attribute_users[-1] = {}
1.41 self.scope_usage[-1] = abandoned_branch_scope
1.42
1.43 + if retain_branch:
1.44 + self.abandoned_users[-1].append(attribute_users)
1.45 +
1.46 def _suspend_broken_branch(self):
1.47
1.48 """
1.49 @@ -785,10 +798,9 @@
1.50
1.51 attribute_users = self.attribute_users[-1]
1.52
1.53 - if not isinstance(attribute_users, AbandonedBranchUsers):
1.54 - users = self.suspended_broken_users[-1]
1.55 - users.append(attribute_users)
1.56 - self._abandon_branch()
1.57 + users = self.suspended_broken_users[-1]
1.58 + users.append(attribute_users)
1.59 + self._abandon_branch(False)
1.60
1.61 def _suspend_continuing_branch(self):
1.62
1.63 @@ -798,10 +810,9 @@
1.64
1.65 attribute_users = self.attribute_users[-1]
1.66
1.67 - if not isinstance(attribute_users, AbandonedBranchUsers):
1.68 - loop_node, users = self.suspended_continuing_users[-1]
1.69 - users.append(attribute_users)
1.70 - self._abandon_branch()
1.71 + loop_node, users = self.suspended_continuing_users[-1]
1.72 + users.append(attribute_users)
1.73 + self._abandon_branch(False)
1.74
1.75 def _shelve_branch(self):
1.76
1.77 @@ -833,6 +844,12 @@
1.78 new_users = merge_mapping_dicts(all_shelved_users)
1.79 self.attribute_users[-1] = new_users
1.80
1.81 + # Abandoned users are retained for exception handling purposes.
1.82 +
1.83 + all_abandoned_users = self.abandoned_users.pop()
1.84 + new_abandoned_users = merge_mapping_dicts(all_abandoned_users)
1.85 + self.abandoned_users[-1].append(new_abandoned_users)
1.86 +
1.87 # Combine the scope usage.
1.88
1.89 scope_usage = self.scope_usage[-1]
1.90 @@ -919,6 +936,18 @@
1.91 new_users = merge_mapping_dicts(suspended_users + [current_users])
1.92 self.attribute_users[-1] = new_users
1.93
1.94 + def _resume_abandoned_branches(self):
1.95 +
1.96 + """
1.97 + Incorporate users from abandoned branches into the current set of active
1.98 + users. The abandoned branches are taken from the containing branch.
1.99 + """
1.100 +
1.101 + current_users = self.attribute_users[-1]
1.102 + abandoned_users = self.abandoned_users[-2]
1.103 + new_users = merge_mapping_dicts(abandoned_users + [current_users])
1.104 + self.attribute_users[-1] = new_users
1.105 +
1.106 # Scope usage methods.
1.107
1.108 def define_scope(self, name, scope):
1.109 @@ -979,15 +1008,6 @@
1.110
1.111 values = items = keys
1.112
1.113 -class AbandonedBranchUsers(EmptyDict):
1.114 -
1.115 - """
1.116 - A class providing a value or state for an abandoned branch distinct from an
1.117 - empty usage dictionary.
1.118 - """
1.119 -
1.120 - pass
1.121 -
1.122 class AbandonedBranchScope(EmptyDict):
1.123
1.124 """
1.125 @@ -997,7 +1017,6 @@
1.126
1.127 pass
1.128
1.129 -abandoned_branch_users = AbandonedBranchUsers()
1.130 abandoned_branch_scope = AbandonedBranchScope()
1.131
1.132 class ScopeConflict:
2.1 --- a/micropython/inspect.py Sun Jun 10 18:38:37 2012 +0200
2.2 +++ b/micropython/inspect.py Sun Jun 10 21:50:53 2012 +0200
2.3 @@ -410,6 +410,9 @@
2.4 def resume_continuing_branches(self):
2.5 self.get_namespace()._resume_continuing_branches()
2.6
2.7 + def resume_abandoned_branches(self):
2.8 + self.get_namespace()._resume_abandoned_branches()
2.9 +
2.10 def define_attribute_user(self, node):
2.11
2.12 """
2.13 @@ -1216,15 +1219,16 @@
2.14 return self._visitOperator(node, self.in_assignment and "AssSubscript" or "Subscript")
2.15
2.16 def visitTryExcept(self, node):
2.17 + self.new_branchpoint()
2.18 self.dispatch(node.body)
2.19
2.20 - self.new_branchpoint()
2.21 -
2.22 - # NOTE: Attempt to recover abandoned branches from the body.
2.23 -
2.24 for name, var, n in node.handlers:
2.25 self.new_branch(n)
2.26
2.27 + # Any abandoned branches from the body can now be resumed.
2.28 +
2.29 + self.resume_abandoned_branches()
2.30 +
2.31 # Establish the local for the handler.
2.32
2.33 if var is not None:
2.34 @@ -1234,6 +1238,10 @@
2.35
2.36 self.shelve_branch()
2.37
2.38 + # The else clause maintains the usage from the body but without the
2.39 + # abandoned branches since they would never lead to the else clause
2.40 + # being executed.
2.41 +
2.42 self.new_branch(node.else_ or NullBranch())
2.43 if node.else_ is not None:
2.44 self.dispatch(node.else_)