1.1 --- a/micropython/data.py Tue Feb 09 23:32:27 2010 +0100
1.2 +++ b/micropython/data.py Wed Feb 10 01:25:48 2010 +0100
1.3 @@ -127,6 +127,7 @@
1.4 self.attribute_shelves = [] # stack of unmerged definitions
1.5 self.attribute_users = [{}] # stack of assignments
1.6 self.abandon_attributes = 0 # used when a block will never contribute
1.7 + self.attributes_abandoned = [{}]
1.8 self.abandoned_shelves = []
1.9 self.all_attributes_used = []
1.10
1.11 @@ -341,15 +342,21 @@
1.12 "Define 'node' as the user of attributes for the given 'name'."
1.13
1.14 defs = self.attributes_used[-1]
1.15 + abandoned_defs = self.attributes_abandoned[-1]
1.16 users = self.attribute_users[-1]
1.17 +
1.18 users[name] = node
1.19 defs[name] = set()
1.20 + abandoned_defs[name] = set()
1.21
1.22 # Record the attribute combinations for the name.
1.23
1.24 if not hasattr(node, "_attrnames"):
1.25 node._attrnames = {}
1.26 + node._attrnames_abandoned = {}
1.27 +
1.28 node._attrnames[name] = defs[name]
1.29 + node._attrnames_abandoned[name] = abandoned_defs[name]
1.30
1.31 # Remember all attribute combinations.
1.32
1.33 @@ -370,16 +377,44 @@
1.34 self.abandon_attributes = 1
1.35
1.36 def _shelve_branch(self):
1.37 +
1.38 + """
1.39 + Shelve the current control-flow branch, recording the attribute usage
1.40 + for subsequent merging. If this branch should be abandoned, the usage
1.41 + observations are still recorded but will not contribute to subsequent
1.42 + observations after a merge.
1.43 + """
1.44 +
1.45 if not self.abandon_attributes:
1.46 collector = self.attribute_shelves[-1]
1.47 else:
1.48 collector = self.abandoned_shelves[-1]
1.49 +
1.50 collector.append(self.attributes_used.pop())
1.51 +
1.52 + # Forget about any nodes which defined names employing attributes in
1.53 + # this branch.
1.54 +
1.55 self.attribute_users.pop()
1.56 self.abandon_attributes = 0
1.57
1.58 def _merge_branches(self):
1.59 +
1.60 + """
1.61 + Merge control-flow branches. This should find the intersection of the
1.62 + usage contributions from each branch, which have been "shelved", and
1.63 + update the active usage dictionary with these contributions.
1.64 +
1.65 + Where branches are "abandoned", their attribute usage will not affect
1.66 + the subsequent usage observations, but such usage will be recorded in
1.67 + order to deduce function usage.
1.68 + """
1.69 +
1.70 + # The active dictionary holds the usage for names defined before the
1.71 + # branches. The abandoned dictionary collects abandoned usage.
1.72 +
1.73 active = self.attributes_used[-1]
1.74 + abandoned = self.attributes_abandoned[-1]
1.75
1.76 # Take each alternative branch, currently shelved, and find the
1.77 # intersection of their contributions for each name.
1.78 @@ -406,6 +441,17 @@
1.79 else:
1.80 active[name] = attrnames
1.81
1.82 + # Where abandoned branches exist, record their contributions for the
1.83 + # attribute users only.
1.84 +
1.85 + if abandoned_defs:
1.86 + for defs in abandoned_defs:
1.87 + for name, attrnames in defs.items():
1.88 + if abandoned.has_key(name):
1.89 + abandoned[name].add(tuple(attrnames))
1.90 + else:
1.91 + abandoned[name] = attrnames
1.92 +
1.93 # Where each shelved set of definitions is a superset of the eventual
1.94 # definitions for a name, record these specialised sets of usage.
1.95