# HG changeset patch # User Paul Boddie # Date 1265504535 -3600 # Node ID c4a46d7fb328c18bd918a688838c2fb847d8fe7c # Parent ab4dcd04e98d5a71ccab60ac665eb93232d7b8ae Distinguished between class and instance attributes when generating guards for attribute users. Added a test of instance-specific guards. Added a documentation note about closures. diff -r ab4dcd04e98d -r c4a46d7fb328 docs/related.txt --- a/docs/related.txt Sat Feb 06 21:00:28 2010 +0100 +++ b/docs/related.txt Sun Feb 07 02:02:15 2010 +0100 @@ -22,3 +22,8 @@ http://mail.python.org/pipermail/python-list/2009-November/1227265.html http://groups.google.com/group/comp.lang.python/browse_frm/thread/c07268689549cf01/ + +A discussion of how closures often obscure intent and how the use of classes +and functions is often preferable: + +http://artificialcode.blogspot.com/2009/04/python-functional-programming.html diff -r ab4dcd04e98d -r c4a46d7fb328 micropython/table.py --- a/micropython/table.py Sat Feb 06 21:00:28 2010 +0100 +++ b/micropython/table.py Sun Feb 07 02:02:15 2010 +0100 @@ -3,7 +3,7 @@ """ Preparation of run-time attribute lookup tables. -Copyright (C) 2007, 2008 Paul Boddie +Copyright (C) 2007, 2008, 2009, 2010 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -353,6 +353,37 @@ list_class = ObjectList + def all_possible_objects_plus_status(self, names): + + """ + Return all objects supporting attributes with the given 'names' plus + whether such attributes can be exclusively static or may belong to + instances. A list of tuples of the form (object name, is_static) is thus + returned. + """ + + possible = [] + for objname in self.all_possible_objects(names): + attributes = self.table[objname] + + is_static = 0 + is_instance = 0 + + for name in names: + if attributes[name].is_static_attribute(): + is_static = 1 + else: + is_instance = 1 + + if is_static and not is_instance: + is_static = 1 + else: + is_static = 0 + + possible.append((objname, is_static)) + + return possible + class ParameterTable(Table): "A parameter table." diff -r ab4dcd04e98d -r c4a46d7fb328 micropython/trans.py --- a/micropython/trans.py Sat Feb 06 21:00:28 2010 +0100 +++ b/micropython/trans.py Sun Feb 07 02:02:15 2010 +0100 @@ -317,13 +317,13 @@ # Get the names of all object types supporting these names. - target_names = self.objtable.all_possible_objects(names_used) + targets = self.objtable.all_possible_objects_plus_status(names_used) # Where only one object type is suggested, produce a guard. # NOTE: This only supports classes as types, not modules. - if len(target_names) == 1: - target_name = target_names[0] + if len(targets) == 1: + target_name, is_static = targets[0] # Access the object table to get the attribute. # NOTE: This depends on the special entry in the table @@ -343,15 +343,22 @@ self.new_op(LoadClass(attr)) temp_target = self.optimiser.optimise_temp_storage() - # Generate name is target (for classes). + # For only static attributes, classes are acceptable. + + if is_static: + + # Generate name is target (for classes). - self.dispatch(compiler.ast.Name(name)) - self.new_op(TestIdentity()) - self.optimiser.set_source(temp_target) + self.dispatch(compiler.ast.Name(name)) + self.new_op(TestIdentity()) + self.optimiser.set_source(temp_target) - # Jump to the next guard or the code if successful. + # Jump to the next guard or the code if successful. - self.new_op(JumpIfTrue(after_test_block)) + self.new_op(JumpIfTrue(after_test_block)) + + # Where instance attributes are involved, only instances are + # acceptable. # Generate isinstance(name, target). diff -r ab4dcd04e98d -r c4a46d7fb328 tests/attribute_access_type_restriction_single_instance.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/attribute_access_type_restriction_single_instance.py Sun Feb 07 02:02:15 2010 +0100 @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +""" +This test attempts to guard 'obj' in 'test_one' with only an instance check for +D instances. In the process, the unused methods should be discarded. +""" + +class C: + def f(self): # unused + return 1 + +class D: + def f(self): + return 2 + + def __init__(self, g): + self.g = g + +class E: + def f(self): # unused + return 4 + + def h(self): # unused + return 5 + +def test_one(obj): + # obj: D (f, g) + obj.f() # C, D, E (f) + return obj.g # D (f, g) - instance only + +c = C() +d = D(4) +e = E() +result1_4 = test_one(d) + +# vim: tabstop=4 expandtab shiftwidth=4