# HG changeset patch # User Paul Boddie # Date 1257120398 -3600 # Node ID 7afcab571b699a936d1019d46e92849c4268e541 # Parent a1e36f5cc00112c51eb70c90b8c66788f0b903ec Changed else clause handling for attribute usage; added break and continue support. Added an AST node annotation for attribute names used in an access operation. Improved the attribute access test program. diff -r a1e36f5cc001 -r 7afcab571b69 micropython/data.py --- a/micropython/data.py Tue Oct 27 00:23:28 2009 +0100 +++ b/micropython/data.py Mon Nov 02 01:06:38 2009 +0100 @@ -283,11 +283,15 @@ if not defs.has_key(name): defs[name] = set() defs[name].add(attrname) + return defs[name] def _reset_attributes(self, name): defs = self.attributes_used[-1] defs[name] = set() + def _reset_all_attributes(self): + self.attributes_used[-1] = {} + def _new_branchpoint(self): self.attribute_shelves.append([]) @@ -309,11 +313,11 @@ for next_defs in shelved_defs[1:]: for name, attrnames in next_defs.items(): if defs.has_key(name): - defs[name].intersection_update(attrnames) + defs[name] = defs[name].intersection(attrnames) for name, attrnames in defs.items(): if active.has_key(name): - active[name].intersection_update(attrnames) + active[name] = active[name].intersection(attrnames) else: active[name] = attrnames diff -r a1e36f5cc001 -r 7afcab571b69 micropython/inspect.py --- a/micropython/inspect.py Tue Oct 27 00:23:28 2009 +0100 +++ b/micropython/inspect.py Mon Nov 02 01:06:38 2009 +0100 @@ -314,8 +314,11 @@ def reset_attributes(self, name): self.get_namespace()._reset_attributes(name) + def reset_all_attributes(self): + self.get_namespace()._reset_all_attributes() + def use_attribute(self, attr, attrname): - self.get_namespace()._use_attribute(attr, attrname) + return self.get_namespace()._use_attribute(attr, attrname) # Visitor methods. @@ -449,7 +452,7 @@ # Note usage of the attribute. if expr.parent is self.get_namespace(): - self.use_attribute(expr, node.attrname) + node._attrnames = self.use_attribute(expr, node.attrname) return None @@ -510,7 +513,8 @@ visitBitxor = _visitBinary - visitBreak = NOP + def visitBreak(self, node): + self.reset_all_attributes() visitCallFunc = OP @@ -589,7 +593,8 @@ self.use_name(self.importer.get_constant_type_name(node.value)) return self.importer.make_constant(node.value) - visitContinue = NOP + def visitContinue(self, node): + self.reset_all_attributes() visitDecorators = NOP @@ -619,6 +624,7 @@ self.dispatch(node.list) # Enter the loop. + # Propagate attribute usage to branches. self.in_loop = 1 self.new_branch() @@ -626,10 +632,13 @@ self.shelve_branch() self.in_loop = 0 + # Maintain a branch for the else clause or the current retained usage + # where execution avoids the conditional clauses. + + self.new_branch() if node.else_ is not None: - self.new_branch() self.dispatch(node.else_) - self.shelve_branch() + self.shelve_branch() self.merge_branches() return None @@ -691,7 +700,7 @@ # Note usage of the attribute. if expr.parent is self.get_namespace(): - self.use_attribute(expr, attrname) + node._attrnames = self.use_attribute(expr, attrname) elif self.builtins is not None: attr = self.builtins.get(attrname) @@ -716,6 +725,8 @@ def visitIf(self, node): self.new_branchpoint() + # Propagate attribute usage to branches. + for test, body in node.tests: self.dispatch(test) @@ -723,10 +734,13 @@ self.dispatch(body) self.shelve_branch() + # Maintain a branch for the else clause or the current retained usage + # where execution avoids the conditional clauses. + + self.new_branch() if node.else_ is not None: - self.new_branch() self.dispatch(node.else_) - self.shelve_branch() + self.shelve_branch() self.merge_branches() return None @@ -863,6 +877,8 @@ def visitWhile(self, node): self.new_branchpoint() + # Propagate attribute usage to branches. + self.in_loop = 1 self.dispatch(node.test) self.new_branch() @@ -870,10 +886,13 @@ self.shelve_branch() self.in_loop = 0 + # Maintain a branch for the else clause or the current retained usage + # where execution avoids the conditional clauses. + + self.new_branch() if node.else_ is not None: - self.new_branch() self.dispatch(node.else_) - self.shelve_branch() + self.shelve_branch() self.merge_branches() return None diff -r a1e36f5cc001 -r 7afcab571b69 tests/attribute_access_type_restriction.py --- a/tests/attribute_access_type_restriction.py Tue Oct 27 00:23:28 2009 +0100 +++ b/tests/attribute_access_type_restriction.py Mon Nov 02 01:06:38 2009 +0100 @@ -11,34 +11,63 @@ def g(self): return 3 +class E: + def f(self): + return 4 + + def h(self): + return 5 + def test_one(obj): - obj.f() - return obj.g() + obj.f() # C, D, E -> D + return obj.g() # D + # obj: D -def test_neither(obj, obj2): - if obj.f(): +def test_two(obj, obj2): + if obj.f(): # C, D, E (f) + obj.g() # D (f, g) + # else: + # ... # obj: C, D, E (f) + # # (f, g) ^ (f) + return 2 + # obj: C, D, E (f) + +def test_new(obj, obj2): + if obj.f(): # C, D, E (f) obj = obj2 - obj.g() - return 2 - -def test_either(obj, obj2): - if obj: - obj = obj2 - obj.g() - return obj.f() + obj.g() # D (g) + # else: + # ... # obj: C, D, E (f) + # # (g) ^ (f) + return obj.f() # C, D, E (f) + # obj: C, D, E (f) def test_neither2(obj, obj2): - if obj: - obj.g() + if 0: + obj.g() # D (g) else: - obj.f() + obj.f() # C, D, E (f) + # # (g) ^ (f) return 4 + # obj: + +def test_three(obj, obj2): + if obj.f(): # C, D, E (f) + obj = obj2 + obj.g() # D (g) + else: + obj.h() # E (f, h) + # # (g) ^ (f, h) + return 5 + # obj: c = C() d = D() +e = E() result1_3 = test_one(d) -result1_2 = test_neither(c, d) -result2_2 = test_either(c, d) +result1_2 = test_two(c, d) +result2_2 = test_new(c, d) result1_4 = test_neither2(c, d) +result1_5 = test_three(e, d) # vim: tabstop=4 expandtab shiftwidth=4