Author: Tyler Wade <way...@gmail.com> Branch: fix-bytearray-complexity Changeset: r71878:5e3423ac75bf Date: 2014-06-01 05:26 -0500 http://bitbucket.org/pypy/pypy/changeset/5e3423ac75bf/
Log: Add to RPython support for __getitem__, __setitem, __getslice__, __setslice__, and __len__ diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -719,6 +719,14 @@ return super(thistype, pair(ins1, ins2)).improve() +class __extend__(pairtype(SomeInstance, SomeObject)): + def getitem((s_ins, s_idx)): + return s_ins._emulate_call("__getitem__", s_idx) + + def setitem((s_ins, s_idx), s_value): + return s_ins._emulate_call("__setitem__", s_idx, s_value) + + class __extend__(pairtype(SomeIterator, SomeIterator)): def union((iter1, iter2)): diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3937,6 +3937,78 @@ s = a.build_types(fn, [int]) assert isinstance(s, annmodel.SomeInteger) + def test_instance_getitem(self): + class A(object): + def __getitem__(self, i): + return i * i + + def fn(i): + a = A() + return a[i] + + a = self.RPythonAnnotator() + s = a.build_types(fn, [int]) + assert len(a.translator.graphs) == 2 # fn, __getitem__ + assert isinstance(s, annmodel.SomeInteger) + + def test_instance_setitem(self): + class A(object): + def __setitem__(self, i, v): + self.value = i * v + + def fn(i, v): + a = A() + a[i] = v + return a.value + + a = self.RPythonAnnotator() + s = a.build_types(fn, [int, int]) + assert len(a.translator.graphs) == 2 # fn, __setitem__ + assert isinstance(s, annmodel.SomeInteger) + + def test_instance_getslice(self): + class A(object): + def __getslice__(self, stop, start): + return "Test"[stop:start] + + def fn(): + a = A() + return a[0:2] + + a = self.RPythonAnnotator() + s = a.build_types(fn, []) + assert len(a.translator.graphs) == 2 # fn, __getslice__ + assert isinstance(s, annmodel.SomeString) + + def test_instance_setslice(self): + class A(object): + def __setslice__(self, stop, start, value): + self.value = value + + def fn(): + a = A() + a[0:2] = '00' + return a.value + + a = self.RPythonAnnotator() + s = a.build_types(fn, []) + assert len(a.translator.graphs) == 2 # fn, __setslice__ + assert isinstance(s, annmodel.SomeString) + + def test_instance_len(self): + class A(object): + def __len__(self): + return 0 + + def fn(): + a = A() + return len(a) + + a = self.RPythonAnnotator() + s = a.build_types(fn, []) + assert len(a.translator.graphs) == 2 # fn, __len__ + assert isinstance(s, annmodel.SomeInteger) + def test_reversed(self): def fn(n): for elem in reversed([1, 2, 3, 4, 5]): diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py --- a/rpython/annotator/unaryop.py +++ b/rpython/annotator/unaryop.py @@ -683,19 +683,27 @@ if not self.can_be_None: s.const = True + def _emulate_call(self, meth_name, *args_s): + bk = getbookkeeper() + s_attr = self._true_getattr(meth_name) + # record for calltables + bk.emulate_pbc_call(bk.position_key, s_attr, args_s) + return s_attr.call(simple_args(args_s)) + def iter(self): - s_iterable = self._true_getattr('__iter__') - bk = getbookkeeper() - # record for calltables - bk.emulate_pbc_call(bk.position_key, s_iterable, []) - return s_iterable.call(simple_args([])) + return self._emulate_call('__iter__') def next(self): - s_next = self._true_getattr('next') - bk = getbookkeeper() - # record for calltables - bk.emulate_pbc_call(bk.position_key, s_next, []) - return s_next.call(simple_args([])) + return self._emulate_call('next') + + def len(self): + return self._emulate_call('__len__') + + def getslice(self, s_start, s_stop): + return self._emulate_call('__getslice__', s_start, s_stop) + + def setslice(self, s_start, s_stop, s_iterable): + return self._emulate_call('__setslice__', s_start, s_stop, s_iterable) class __extend__(SomeBuiltin): def simple_call(self, *args): diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py --- a/rpython/rlib/buffer.py +++ b/rpython/rlib/buffer.py @@ -12,6 +12,9 @@ def getlength(self): raise NotImplementedError + def __len__(self): + return self.getlength() + def as_str(self): "Returns an interp-level string with the whole content of the buffer." # May be overridden. @@ -21,14 +24,23 @@ "Returns the index'th character in the buffer." raise NotImplementedError # Must be overriden. No bounds checks. + def __getitem__(self, i): + return self.getitem(i) + def getslice(self, start, stop, step, size): # May be overridden. No bounds checks. return ''.join([self.getitem(i) for i in range(start, stop, step)]) + def __getslice__(self, start, stop): + return self.getslice(start, stop, 1, stop - start) + def setitem(self, index, char): "Write a character into the buffer." raise NotImplementedError # Must be overriden. No bounds checks. + def __setitem__(self, i, char): + return self.setitem(i, char) + def setslice(self, start, string): # May be overridden. No bounds checks. for i in range(len(string)): diff --git a/rpython/rlib/test/test_buffer.py b/rpython/rlib/test/test_buffer.py --- a/rpython/rlib/test/test_buffer.py +++ b/rpython/rlib/test/test_buffer.py @@ -4,7 +4,10 @@ def test_string_buffer(): buf = StringBuffer('hello world') assert buf.getitem(4) == 'o' + assert buf.getitem(4) == buf[4] assert buf.getlength() == 11 + assert buf.getlength() == len(buf) assert buf.getslice(1, 6, 1, 5) == 'ello ' + assert buf.getslice(1, 6, 1, 5) == buf[1:6] assert buf.getslice(1, 6, 2, 3) == 'el ' assert buf.as_str() == 'hello world' diff --git a/rpython/rtyper/rclass.py b/rpython/rtyper/rclass.py --- a/rpython/rtyper/rclass.py +++ b/rpython/rtyper/rclass.py @@ -7,6 +7,7 @@ from rpython.rtyper.lltypesystem.lltype import Void from rpython.rtyper.rmodel import Repr, getgcflavor, inputconst from rpython.rlib.objectmodel import UnboxedValue +from rpython.tool.pairtype import pairtype class FieldListAccessor(object): @@ -390,7 +391,7 @@ raise NotImplementedError def _emulate_call(self, hop, meth_name): - vinst, = hop.inputargs(self) + vinst = hop.args_v[0] clsdef = hop.args_s[0].classdef s_unbound_attr = clsdef.find_attribute(meth_name).getvalue() s_attr = clsdef.lookup_filter(s_unbound_attr, meth_name, @@ -402,10 +403,10 @@ r_method = self.rtyper.getrepr(s_attr) r_method.get_method_from_instance(self, vinst, hop.llops) hop2 = hop.copy() - hop2.spaceop = op.simple_call(hop.spaceop.args[0]) + hop2.spaceop = op.simple_call(*hop.spaceop.args) hop2.spaceop.result = hop.spaceop.result - hop2.args_r = [r_method] - hop2.args_s = [s_attr] + hop2.args_r[0] = r_method + hop2.args_s[0] = s_attr return hop2.dispatch() def rtype_iter(self, hop): @@ -414,6 +415,15 @@ def rtype_next(self, hop): return self._emulate_call(hop, 'next') + def rtype_getslice(self, hop): + return self._emulate_call(hop, "__getslice__") + + def rtype_setslice(self, hop): + return self._emulate_call(hop, "__setslice__") + + def rtype_len(self, hop): + return self._emulate_call(hop, "__len__") + def ll_str(self, i): raise NotImplementedError @@ -460,6 +470,16 @@ if len(seen) == oldlength: break + +class __extend__(pairtype(AbstractInstanceRepr, Repr)): + def rtype_getitem((r_ins, r_obj), hop): + return r_ins._emulate_call(hop, "__getitem__") + + def rtype_setitem((r_ins, r_obj), hop): + return r_ins._emulate_call(hop, "__setitem__") + + + # ____________________________________________________________ def rtype_new_instance(rtyper, classdef, llops, classcallhop=None): diff --git a/rpython/rtyper/test/test_rclass.py b/rpython/rtyper/test/test_rclass.py --- a/rpython/rtyper/test/test_rclass.py +++ b/rpython/rtyper/test/test_rclass.py @@ -1193,6 +1193,69 @@ assert self.interpret(f, [True]) == f(True) assert self.interpret(f, [False]) == f(False) + def test_indexing(self): + class A(object): + def __init__(self, data): + self.data = data + + def __getitem__(self, i): + return self.data[i] + + def __setitem__(self, i, v): + self.data[i] = v + + def __getslice__(self, start, stop): + assert start >= 0 + assert stop >= 0 + return self.data[start:stop] + + def __setslice__(self, start, stop, v): + assert start >= 0 + assert stop >= 0 + i = 0 + for n in range(start, stop): + self.data[n] = v[i] + i += 1 + + def getitem(i): + a = A("abcdefg") + return a[i] + + def setitem(i, v): + a = A([0] * 5) + a[i] = v + return a[i] + + def getslice(start, stop): + a = A([1, 2, 3, 4, 5, 6]) + sum = 0 + for i in a[start:stop]: + sum += i + return sum + + def setslice(start, stop, i): + a = A([0] * stop) + a[start:stop] = range(start, stop) + return a[i] + + assert self.interpret(getitem, [0]) == getitem(0) + assert self.interpret(getitem, [1]) == getitem(1) + assert self.interpret(setitem, [0, 5]) == setitem(0, 5) + assert self.interpret(getslice, [0, 4]) == getslice(0, 4) + assert self.interpret(getslice, [1, 4]) == getslice(1, 4) + assert self.interpret(setslice, [4, 6, 5]) == setslice(4, 6, 5) + + def test_len(self): + class A(object): + def __len__(self): + return 5 + + def fn(): + a = A() + return len(a) + + assert self.interpret(fn, []) == fn() + def test_init_with_star_args(self): class Base(object): def __init__(self, a, b): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit