1.1 --- a/micropython/__init__.py Wed Jul 04 01:25:34 2012 +0200
1.2 +++ b/micropython/__init__.py Fri Jul 06 01:52:10 2012 +0200
1.3 @@ -94,8 +94,6 @@
1.4
1.5 "Finalise the program."
1.6
1.7 - self.importer.complete_modules()
1.8 -
1.9 # Need the tables to finalise.
1.10
1.11 objtable = self.get_object_table()
1.12 @@ -442,7 +440,6 @@
1.13
1.14 # Status information.
1.15
1.16 - self.completed = 0
1.17 self.vacuumed = 0
1.18 self.finalised = 0
1.19
1.20 @@ -458,28 +455,6 @@
1.21
1.22 return self.modules[name]
1.23
1.24 - def complete_modules(self):
1.25 -
1.26 - "Complete the processing of modules."
1.27 -
1.28 - if self.completed:
1.29 - return
1.30 -
1.31 - processed = set()
1.32 - modules = self.get_modules()
1.33 -
1.34 - while len(processed) != len(modules):
1.35 - for module in modules:
1.36 - if module in processed:
1.37 - continue
1.38 - if self.verbose:
1.39 - print >>sys.stderr, "Completing", module.full_name()
1.40 - module.process_functions()
1.41 - processed.add(module)
1.42 - modules = self.get_modules()
1.43 -
1.44 - self.completed = 1
1.45 -
1.46 # General maintenance.
1.47
1.48 def vacuum(self, objtable):
2.1 --- a/micropython/data.py Wed Jul 04 01:25:34 2012 +0200
2.2 +++ b/micropython/data.py Fri Jul 06 01:52:10 2012 +0200
2.3 @@ -1061,13 +1061,19 @@
2.4 return [v for (c, v) in self.context_values]
2.5
2.6 def get_context(self):
2.7 - if len(self.context_values) == 1:
2.8 +
2.9 + "Get the context referenced by the attribute."
2.10 +
2.11 + if self.assignments == 1 and len(self.context_values) == 1:
2.12 return self.get_contexts()[0]
2.13 else:
2.14 return None
2.15
2.16 def get_value(self):
2.17 - if len(self.context_values) == 1:
2.18 +
2.19 + "Get the value referenced by the attribute."
2.20 +
2.21 + if self.assignments == 1 and len(self.context_values) == 1:
2.22 return self.get_values()[0]
2.23 else:
2.24 return None
2.25 @@ -1089,18 +1095,20 @@
2.26 not (make_instance(), make_instance()) in context_values:
2.27 return
2.28
2.29 + self.update_assignments(len(set(context_values)), single_assignment)
2.30 + self.context_values.update(context_values)
2.31 +
2.32 + def update_assignments(self, n, single_assignment):
2.33 if self.assignments is None:
2.34 if single_assignment:
2.35 - self.assignments = len(set(context_values))
2.36 + self.assignments = n
2.37 else:
2.38 - self.assignments = AtLeast(len(set(context_values)))
2.39 + self.assignments = AtLeast(n)
2.40 else:
2.41 if single_assignment:
2.42 - self.assignments += 1
2.43 + self.assignments += n
2.44 else:
2.45 - self.assignments += AtLeast(1)
2.46 -
2.47 - self.context_values.update(context_values)
2.48 + self.assignments += AtLeast(n)
2.49
2.50 def is_constant(self):
2.51
2.52 @@ -2061,6 +2069,24 @@
2.53
2.54 return dict(self)
2.55
2.56 + def modify_name(self, name):
2.57 +
2.58 + """
2.59 + Modify a global 'name' invalidating various assumptions about its
2.60 + behaviour based on the module namespace being "safe" and suitable for
2.61 + attribute usage and constant value observations.
2.62 + """
2.63 +
2.64 + self.modified_names.add(name)
2.65 +
2.66 + # Establish an attribute directly in the namespace if not present.
2.67 +
2.68 + if not self.namespace.has_key(name):
2.69 + self.namespace[name] = Attr(None, self, name)
2.70 +
2.71 + attr = self.namespace[name]
2.72 + attr.update_assignments(1, False)
2.73 +
2.74 # Attribute usage methods that apply to module globals in certain
2.75 # circumstances.
2.76
3.1 --- a/micropython/inspect.py Wed Jul 04 01:25:34 2012 +0200
3.2 +++ b/micropython/inspect.py Fri Jul 06 01:52:10 2012 +0200
3.3 @@ -90,9 +90,8 @@
3.4 order:
3.5
3.6 1. parse
3.7 - 2. process_functions
3.8 - 3. vacuum
3.9 - 4. finalise
3.10 + 2. vacuum
3.11 + 3. finalise
3.12
3.13 A module importer can be expected to perform these invocations.
3.14 """
3.15 @@ -158,6 +157,10 @@
3.16
3.17 self.finalise_attribute_usage()
3.18
3.19 + # Visit functions.
3.20 +
3.21 + self.process_functions()
3.22 +
3.23 # Add references to other modules declared using the __all__ global.
3.24
3.25 if self.has_key("__all__"):
3.26 @@ -196,11 +199,11 @@
3.27 for name in n.names:
3.28
3.29 # Each name may potentially be assigned many times.
3.30 - # NOTE: We don't try and find out the specifics at this
3.31 - # NOTE: point and just set an instance instead.
3.32 + # We don't try and find out the specifics at this point and
3.33 + # just indicate that the name cannot be relied upon for
3.34 + # various observations.
3.35
3.36 - self.set(name, make_instance(), False)
3.37 - self.modified_names.add(name)
3.38 + module.modify_name(name)
3.39
3.40 else:
3.41 self.process_globals(n)
3.42 @@ -1007,8 +1010,8 @@
3.43 if module and not module.loaded:
3.44 print >>sys.stderr, "Warning: a circular import of %s is being attempted in %s" % (node.modname, self.full_name())
3.45
3.46 - #if module is None:
3.47 - # print >>sys.stderr, "Warning:", node.modname, "not imported."
3.48 + if module is None and self.importer.verbose:
3.49 + print >>sys.stderr, "Warning:", node.modname, "not imported."
3.50
3.51 for name, alias in node.names:
3.52
3.53 @@ -1036,7 +1039,16 @@
3.54 self.store(alias or name, attr)
3.55 self.use_specific_attribute(module.full_name(), name)
3.56 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
3.57 - self.importer.load(attr.get_value().name, importer=node)
3.58 + submodule = self.importer.load(attr.get_value().name, importer=node)
3.59 +
3.60 + # For circular imports, invalidate attribute usage for
3.61 + # all exported names of submodules whose names are
3.62 + # specified in the from statement.
3.63 +
3.64 + if submodule and not submodule.loaded:
3.65 + for n in submodule.keys():
3.66 + submodule.modify_name(n)
3.67 +
3.68 continue
3.69
3.70 # Support the import of names from missing modules.
3.71 @@ -1053,7 +1065,15 @@
3.72 self.store(n, attr)
3.73 self.use_specific_attribute(module.full_name(), n)
3.74 if isinstance(attr.get_value(), Module) and not attr.get_value().loaded:
3.75 - self.importer.load(attr.get_value().name, importer=node)
3.76 + submodule = self.importer.load(attr.get_value().name, importer=node)
3.77 +
3.78 + # For circular imports, invalidate attribute usage
3.79 + # for all exported names of submodules provided by
3.80 + # the module.
3.81 +
3.82 + if submodule and not submodule.loaded:
3.83 + for subn in submodule.keys():
3.84 + submodule.modify_name(subn)
3.85
3.86 def visitFunction(self, node):
3.87 return self._visitFunction(node, node.name)
3.88 @@ -1131,6 +1151,15 @@
3.89 module = self.importer.load(name, importer=node) or UnresolvedName(None, name.split(".")[0], self)
3.90 self.store(name.split(".")[0], module)
3.91
3.92 + circular = module and not module.loaded
3.93 +
3.94 + # For circular imports, invalidate attribute usage for all exported
3.95 + # names of modules.
3.96 +
3.97 + if module and not module.loaded:
3.98 + for n in module.keys():
3.99 + module.modify_name(n)
3.100 +
3.101 visitInvert = _visitUnary
3.102
3.103 def visitKeyword(self, node):
4.1 --- a/tests/changed/__init__.py Wed Jul 04 01:25:34 2012 +0200
4.2 +++ b/tests/changed/__init__.py Fri Jul 06 01:52:10 2012 +0200
4.3 @@ -1,12 +1,18 @@
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 def f():
4.13 import changed.modifier
4.14
4.15 def getx():
4.16 - return x
4.17 + return x.p # ambiguous
4.18
4.19 -x = 123
4.20 +x = C
4.21 f() # import modifier which changes x in this module
4.22
4.23 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/tests/changed/modifier.py Wed Jul 04 01:25:34 2012 +0200
5.2 +++ b/tests/changed/modifier.py Fri Jul 06 01:52:10 2012 +0200
5.3 @@ -4,6 +4,6 @@
5.4
5.5 # Change x in the partially imported module.
5.6
5.7 -changed.x = 456
5.8 +changed.x = changed.D
5.9
5.10 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/tests/changed_globals.py Wed Jul 04 01:25:34 2012 +0200
6.2 +++ b/tests/changed_globals.py Fri Jul 06 01:52:10 2012 +0200
6.3 @@ -2,7 +2,7 @@
6.4
6.5 import changed
6.6
6.7 -result1_456 = changed.x
6.8 +result1_456 = changed.x.p
6.9 result2_456 = changed.getx()
6.10
6.11 # vim: tabstop=4 expandtab shiftwidth=4