micropython

Changeset

540:05abcd0316a5
2012-06-10 Paul Boddie raw files shortlog changelog graph Introduced separate handling of abandoned attribute usage branches so that exception handlers can restore usage from such branches.
micropython/data.py (file) micropython/inspect.py (file)
     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_)