1.1 --- a/TO_DO.txt Tue Jul 03 23:52:27 2012 +0200
1.2 +++ b/TO_DO.txt Wed Jul 04 00:27:29 2012 +0200
1.3 @@ -76,6 +76,8 @@
1.4 types for a name, and the final set of names leading to such type deductions might be a
1.5 useful annotation to be added alongside _attrcombined.
1.6
1.7 + Update the reports to group identical sets of attribute names.
1.8 +
1.9 Interface/Type Generalisation
1.10 -----------------------------
1.11
1.12 @@ -230,9 +232,6 @@
1.13 Consider a separate annotation phase where deductions are added to the AST for the
1.14 benefit of both the reporting and code generation phases.
1.15
1.16 -Support self attribute visualisation in the reports and/or provide a function or
1.17 -annotations which can provide the eventual optimisation directly to such components.
1.18 -
1.19 Check context_value initialisation (avoiding or handling None effectively).
1.20
1.21 Consider better "macro" support where new expressions need to be generated and processed.
2.1 --- a/micropython/data.py Tue Jul 03 23:52:27 2012 +0200
2.2 +++ b/micropython/data.py Wed Jul 04 00:27:29 2012 +0200
2.3 @@ -2015,6 +2015,13 @@
2.4
2.5 self.all_objects = set()
2.6
2.7 + # A dictionary mapping functions to global names that cannot support
2.8 + # combined attribute usage observations because they may be modified in
2.9 + # the given functions during initialisation. Functions could be
2.10 + # eliminated from this dictionary if not thought to be used.
2.11 +
2.12 + self.modified_names = {}
2.13 +
2.14 # Keyword records.
2.15
2.16 self.keyword_names = set()
2.17 @@ -2055,6 +2062,83 @@
2.18
2.19 return dict(self)
2.20
2.21 + # Attribute usage methods that apply to module globals in certain
2.22 + # circumstances.
2.23 +
2.24 + def finalise_users(self, objtable):
2.25 +
2.26 + """
2.27 + Finalise attribute users, first revoking usage for any global names
2.28 + that might be modified during initialisation.
2.29 + """
2.30 +
2.31 + NamespaceDict.finalise_users(self, objtable)
2.32 +
2.33 + # Collect modified names and revoke attribute usage details for those
2.34 + # names.
2.35 +
2.36 + names = set()
2.37 + for function_names in self.modified_names.values():
2.38 + names.update(function_names)
2.39 +
2.40 + self.revoke_attribute_usage(names)
2.41 +
2.42 + def revoke_attribute_usage(self, names):
2.43 +
2.44 + """
2.45 + The definition of attribute users may be overridden or ignored if the
2.46 + module is found to be involved in circular imports where externally
2.47 + initiated modification occurs or if a function in the module may rebind
2.48 + globals, potentially during initialisation.
2.49 + """
2.50 +
2.51 + for user in self.all_attribute_users:
2.52 +
2.53 + # Remove user details for each name.
2.54 +
2.55 + for name in names:
2.56 +
2.57 + # Remove annotations derived from the combined observations.
2.58 +
2.59 + if user._attrtypes.has_key(name):
2.60 + del user._attrtypes[name]
2.61 + if user._attrspecifictypes.has_key(name):
2.62 + del user._attrspecifictypes[name]
2.63 + if user._attrmerged.has_key(name):
2.64 + del user._attrmerged[name]
2.65 +
2.66 + # Usage nodes that can no longer support combined observations
2.67 + # of attribute usage must instead support isolated observations.
2.68 +
2.69 + if not user._attrcombined.has_key(name):
2.70 + continue
2.71 +
2.72 + usage = user._attrcombined[name]
2.73 +
2.74 + # Usage is defined as a collection of attribute name
2.75 + # observations.
2.76 +
2.77 + for attrnames in usage:
2.78 +
2.79 + # Each attribute name may have values associated with it
2.80 + # where such values have been assigned to an attribute of
2.81 + # the given name.
2.82 +
2.83 + for attrname, attrvalues in usage.items():
2.84 + if attrvalues:
2.85 + for value in attrvalues:
2.86 + self.importer.use_name(attrname, self.full_name(), value)
2.87 + else:
2.88 + self.importer.use_name(attrname, self.full_name())
2.89 +
2.90 + del user._attrcombined[name]
2.91 +
2.92 + # Remove annotations on contributors.
2.93 +
2.94 + for contributor in user._attrcontributors:
2.95 + if contributor._attrusers.has_key(name):
2.96 + del contributor._attrusers[name]
2.97 +
2.98 # Pre-made instances.
2.99
2.100 type_class = TypeClass("type") # details to be filled in later
3.1 --- a/micropython/inspect.py Tue Jul 03 23:52:27 2012 +0200
3.2 +++ b/micropython/inspect.py Wed Jul 04 00:27:29 2012 +0200
3.3 @@ -85,6 +85,16 @@
3.4 """
3.5 An inspected module, providing core details via the Module superclass, but
3.6 capable of being used as an AST visitor.
3.7 +
3.8 + A module can be inspected through the invocation of the following methods in
3.9 + order:
3.10 +
3.11 + 1. parse
3.12 + 2. process_functions
3.13 + 3. vacuum
3.14 + 4. finalise
3.15 +
3.16 + A module importer can be expected to perform these invocations.
3.17 """
3.18
3.19 def __init__(self, name, importer):
3.20 @@ -138,16 +148,14 @@
3.21
3.22 self.store("__name__", self._visitConst(self.full_name()))
3.23
3.24 - # First, visit module-level code, recording global names.
3.25 + # Detect and record globals declared in the module.
3.26 +
3.27 + self.process_globals(module)
3.28 +
3.29 + # Visit module-level code, also recording global names.
3.30
3.31 processed = self.dispatch(module)
3.32
3.33 - # Then, for each function, detect and record globals declared in those
3.34 - # functions.
3.35 -
3.36 - for node, namespaces in self.functions:
3.37 - self.process_globals(node)
3.38 -
3.39 self.finalise_attribute_usage()
3.40
3.41 # Add references to other modules declared using the __all__ global.
3.42 @@ -186,8 +194,12 @@
3.43 for n in node.getChildNodes():
3.44 if isinstance(n, compiler.ast.Global):
3.45 for name in n.names:
3.46 - if not self.has_key(name):
3.47 - self[name] = make_instance()
3.48 +
3.49 + # Each name may potentially be assigned many times.
3.50 + # NOTE: We don't try and find out the specifics at this
3.51 + # NOTE: point and just set an instance instead.
3.52 +
3.53 + self.set(name, make_instance(), False)
3.54 else:
3.55 self.process_globals(n)
3.56
3.57 @@ -1067,6 +1079,19 @@
3.58
3.59 # The name is recorded in an earlier process.
3.60
3.61 + # Since the presence of a global declaration may
3.62 + # indicate the modification of a name, and this may
3.63 + # happen during initialisation, the name is recorded
3.64 + # and any usage observations ultimately revoked.
3.65 +
3.66 + # NOTE: Actual modification could be detected by
3.67 + # NOTE: establishing a path from the module top-level to
3.68 + # NOTE: an actual assignment.
3.69 +
3.70 + if not self.modified_names.has_key(ns):
3.71 + self.modified_names[ns] = set()
3.72 + self.modified_names[ns].add(name)
3.73 +
3.74 def visitIf(self, node):
3.75 self.use_name("__bool__", node)
3.76 self.new_branchpoint()
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/tests/changed_globals_function.py Wed Jul 04 00:27:29 2012 +0200
4.3 @@ -0,0 +1,22 @@
4.4 +#!/usr/bin/env python
4.5 +
4.6 +class C:
4.7 + p = 123
4.8 +
4.9 +class D:
4.10 + p = 456
4.11 +
4.12 +x = C
4.13 +
4.14 +def change():
4.15 + global x
4.16 + x = D
4.17 +
4.18 +def f():
4.19 + return x.p
4.20 +
4.21 +change()
4.22 +result1_456 = x.p
4.23 +result2_456 = f()
4.24 +
4.25 +# vim: tabstop=4 expandtab shiftwidth=4