# HG changeset patch # User Paul Boddie # Date 1283554537 -7200 # Node ID c799fef50ca277dfa095699445662614afe63af2 # Parent cf6ae114650f661072c77cdf07587d0a0fed69a0 Made attribute access inspection generic, fixing an issue with unpredictable accesses. Introduced potentially specific attribute access inspection to the Slice and Subscript node handlers. Added a test of slicing. Added type checking for the current list.__getitem__ implementation. diff -r cf6ae114650f -r c799fef50ca2 TO_DO.txt --- a/TO_DO.txt Tue Aug 31 00:59:16 2010 +0200 +++ b/TO_DO.txt Sat Sep 04 00:55:37 2010 +0200 @@ -1,7 +1,20 @@ +Support slicing. This is difficult because __getitem__ has to handle integers and slice +objects differently. One could either just try and iterate over the argument and then +catch the AttributeError for integers, or one could test the instances first. + +Support isinstance. Like slicing, the problem is dealing with the class or tuple input +to the function. A strict tuple check is permissible according to the CPython behaviour, +but an iterable would be more elegant (as would *args). + +Consider attribute usage observations being suspended inside blocks where AttributeError +may be caught (although this doesn't anticipate such exceptions being caught outside a +function altogether). + Fix object table entries for attributes not provided by any known object, or provide an error, potentially overridden by options. For example, the augmented assignment methods are not supported by the built-in objects and thus the operator module functions cause -the compilation to fail. +the compilation to fail. Alternatively, just supply the methods since something has to do +so in the builtins. Support tuple parameters. @@ -45,8 +58,6 @@ __getitem__ could be written in Python, using a native method only to access fragments. -Support slicing. - Consider better "macro" support where new expressions need to be generated and processed. **** Constant attribute users need not maintain usage since they are already resolved. **** diff -r cf6ae114650f -r c799fef50ca2 micropython/inspect.py --- a/micropython/inspect.py Tue Aug 31 00:59:16 2010 +0200 +++ b/micropython/inspect.py Sat Sep 04 00:55:37 2010 +0200 @@ -416,7 +416,7 @@ module = attr.get_value() return module - def _visitUnary(self, node): + def _visitOperator(self, node): "Accounting method for the operator 'node'." @@ -425,7 +425,45 @@ self.use_specific_attribute(operator_module.full_name(), operator_fn) return self.OP(node) - _visitBinary = _visitUnary + _visitBinary = _visitOperator + _visitUnary = _visitOperator + + def _visitAttr(self, expr, attrname, node): + + # Attempt to identify the nature of the attribute. + + if isinstance(expr, Attr): + value = expr.get_value() + + # Get the attribute and record its usage. + + if isinstance(value, (Class, Module)): + attr = value.get(attrname) + self.use_specific_attribute(value.full_name(), attrname) + + elif isinstance(value, UnresolvedName): + attr = UnresolvedName(attrname, value.full_name(), self) + + else: + attr = None + + # Note usage of the attribute where a local is involved. + + if expr.parent is self.get_namespace(): + node._attrusers = self.use_attribute(expr.name, attrname) + node._username = expr.name + else: + self.use_name(attrname, node.expr) + + elif self.builtins is not None: + attr = self.builtins.get(attrname) + self.use_specific_attribute(self.builtins.full_name(), attrname) + + else: + attr = None + self.use_name(attrname, node) + + return attr def _visitFunction(self, node, name): @@ -806,40 +844,7 @@ def visitGetattr(self, node): expr = self.dispatch(node.expr) attrname = node.attrname - - # Attempt to identify the nature of the attribute. - - if isinstance(expr, Attr): - value = expr.get_value() - - # Get the attribute and record its usage. - - if isinstance(value, (Class, Module)): - attr = value.get(attrname) - self.use_specific_attribute(value.full_name(), attrname) - - elif isinstance(value, UnresolvedName): - attr = UnresolvedName(attrname, value.full_name(), self) - - else: - attr = None - - # Note usage of the attribute where a local is involved. - - if expr.parent is self.get_namespace(): - node._attrusers = self.use_attribute(expr.name, attrname) - node._username = expr.name - else: - self.use_name(attrname, node.expr) - - elif self.builtins is not None: - attr = self.builtins.get(attrname) - self.use_specific_attribute(self.builtins.full_name(), attrname) - - else: - attr = UnresolvedName(attrname, value.full_name(), self) - - return attr + return self._visitAttr(expr, attrname, node) def visitGlobal(self, node): if self.namespaces: @@ -972,9 +977,15 @@ visitRightShift = _visitBinary def visitSlice(self, node): + expr = self.dispatch(node.expr) + self._visitAttr(expr, "__getitem__", node) + + if node.lower is not None: + self.dispatch(node.lower) + if node.upper is not None: + self.dispatch(node.upper) + self.use_specific_attribute("__builtins__", "slice") - self.use_name("__getitem__", node) - self.OP(node) visitSliceobj = OP @@ -986,8 +997,11 @@ visitSub = _visitBinary def visitSubscript(self, node): - self.use_name("__getitem__", node) - self.OP(node) + expr = self.dispatch(node.expr) + self._visitAttr(expr, "__getitem__", node) + + for sub in node.subs: + self.dispatch(sub) def visitTryExcept(self, node): self.dispatch(node.body) diff -r cf6ae114650f -r c799fef50ca2 rsvplib.py --- a/rsvplib.py Tue Aug 31 00:59:16 2010 +0200 +++ b/rsvplib.py Sat Sep 04 00:55:37 2010 +0200 @@ -291,16 +291,24 @@ header = self.machine.load(fragment.ref) nelements = header.occupied_size - 1 - # NOTE: Assume single location for data and header. + # Test operand suitability. + + if self.machine._CheckInstance(item_value.ref, self.int_class): - item_pos = self.machine.load(item_value.ref + 1) + # NOTE: Assume single location for data and header. + + item_pos = self.machine.load(item_value.ref + 1) - if item_pos >= 0 and item_pos < nelements: - pass - elif item_pos < 0 and item_pos >= -nelements: - item_pos = nelements + item_pos + if item_pos >= 0 and item_pos < nelements: + pass + elif item_pos < 0 and item_pos >= -nelements: + item_pos = nelements + item_pos + else: + self.machine.exception = self.machine._MakeObject(2, self.index_error_instance) + return self.machine.RaiseException() + else: - self.machine.exception = self.machine._MakeObject(2, self.index_error_instance) + self.machine.exception = self.machine._MakeObject(2, self.type_error_instance) return self.machine.RaiseException() # NOTE: Assume single location for header. diff -r cf6ae114650f -r c799fef50ca2 tests/slice.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/slice.py Sat Sep 04 00:55:37 2010 +0200 @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +l = [1, 2, 3, 4, 5] + +result1_3 = len(l[2:]) +result_2 = len(l[:2]) +result2_3 = len(l[1:4]) + +# vim: tabstop=4 expandtab shiftwidth=4