Commit e6a5b93c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add instance_cls.__delattr__, __iter__, and next

gflags test is passing

Also add file.name
parent 232abd9e
......@@ -636,9 +636,9 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
is an iterator, this returns itself. */
#define PyIter_Check(obj) \
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
(obj)->ob_type->tp_iternext != NULL && \
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
(PyType_HasFeature(Py_TYPE((obj)), Py_TPFLAGS_HAVE_ITER) && \
Py_TYPE((obj))->tp_iternext != NULL && \
Py_TYPE((obj))->tp_iternext != &_PyObject_NextNotImplemented)
PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *) PYSTON_NOEXCEPT;
/* Takes an iterator object and calls its tp_iternext slot,
......
......@@ -333,6 +333,34 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
return None;
}
Box* instanceDelattr(Box* _inst, Box* _attr) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
RELEASE_ASSERT(_attr->cls == str_cls, "");
BoxedString* attr = static_cast<BoxedString*>(_attr);
// These are special cases in CPython as well:
if (attr->s[0] == '_' && attr->s[1] == '_') {
if (attr->s == "__dict__")
raiseExcHelper(TypeError, "__dict__ must be set to a dictionary");
if (attr->s == "__class__")
raiseExcHelper(TypeError, "__class__ must be set to a class");
}
static const std::string delattr_str("__delattr__");
Box* delattr = classLookup(inst->inst_cls, delattr_str);
if (delattr) {
delattr = processDescriptor(delattr, inst, inst->inst_cls);
return runtimeCall(delattr, ArgPassSpec(1), _attr, NULL, NULL, NULL, NULL);
}
_inst->delattr(attr->s, NULL);
return None;
}
static int instance_setattro(Box* cls, Box* attr, Box* value) noexcept {
try {
if (value) {
......@@ -488,6 +516,45 @@ static Box* instanceHash(BoxedInstance* inst) {
}
}
static Box* instanceIter(BoxedInstance* self) {
assert(self->cls == instance_cls);
PyObject* func;
if ((func = _instanceGetattribute(self, boxStrConstant("__iter__"), false)) != NULL) {
PyObject* res = PyEval_CallObject(func, (PyObject*)NULL);
if (!res)
throwCAPIException();
if (!PyIter_Check(res))
raiseExcHelper(TypeError, "__iter__ returned non-iterator of type '%.100s'", res->cls->tp_name);
return res;
}
if ((func = _instanceGetattribute(self, boxStrConstant("__getitem__"), false)) == NULL) {
raiseExcHelper(TypeError, "iteration over non-sequence");
}
Box* r = PySeqIter_New((PyObject*)self);
if (!r)
throwCAPIException();
return r;
}
static Box* instanceNext(BoxedInstance* inst) {
assert(inst->cls == instance_cls);
Box* next_func = _instanceGetattribute(inst, boxStrConstant("next"), false);
if (!next_func) {
// not 100% sure why this is a different error:
raiseExcHelper(TypeError, "instance has no next() method");
}
Box* r = runtimeCall(next_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
return r;
}
static PyObject* instance_index(PyObject* self) noexcept {
PyObject* func, *res;
/*
......@@ -569,6 +636,7 @@ void setupClassobj() {
instance_cls->giveAttr("__getattribute__",
new BoxedFunction(boxRTFunction((void*)instanceGetattribute, UNKNOWN, 2)));
instance_cls->giveAttr("__setattr__", new BoxedFunction(boxRTFunction((void*)instanceSetattr, UNKNOWN, 3)));
instance_cls->giveAttr("__delattr__", new BoxedFunction(boxRTFunction((void*)instanceDelattr, UNKNOWN, 2)));
instance_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)instanceStr, UNKNOWN, 1)));
instance_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)instanceRepr, UNKNOWN, 1)));
instance_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)instanceNonzero, UNKNOWN, 1)));
......@@ -578,6 +646,8 @@ void setupClassobj() {
instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2)));
instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2)));
instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1)));
instance_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)instanceIter, UNKNOWN, 1)));
instance_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)instanceNext, UNKNOWN, 1)));
instance_cls->giveAttr("__call__",
new BoxedFunction(boxRTFunction((void*)instanceCall, UNKNOWN, 1, 0, true, true)));
instance_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)instanceEq, UNKNOWN, 2)));
......
......@@ -1647,6 +1647,8 @@ void setupFile() {
file_cls->giveAttr("tell", new BoxedFunction(boxRTFunction((void*)fileTell, UNKNOWN, 1)));
file_cls->giveAttr("softspace",
new BoxedMemberDescriptor(BoxedMemberDescriptor::INT, offsetof(BoxedFile, f_softspace), false));
file_cls->giveAttr("name",
new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedFile, f_name), true));
file_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)fileNew, UNKNOWN, 4, 2, false, false),
{ boxStrConstant("r"), boxInt(-1) }));
......
......@@ -320,13 +320,10 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_basicsize = instance_size;
tp_weaklistoffset = weaklist_offset;
tp_flags |= Py_TPFLAGS_DEFAULT_EXTERNAL;
tp_flags |= Py_TPFLAGS_CHECKTYPES;
tp_flags |= Py_TPFLAGS_BASETYPE;
tp_flags |= Py_TPFLAGS_HAVE_CLASS;
tp_flags |= Py_TPFLAGS_HAVE_GC;
tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE;
tp_flags |= Py_TPFLAGS_HAVE_INDEX;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
......
......@@ -3,6 +3,7 @@ import tempfile
f = open("/dev/null")
print repr(f.read())
print repr(f.name)
f2 = file("/dev/null")
print repr(f2.read())
......
......@@ -147,9 +147,13 @@ class SetattrTest:
def __setattr__(self, attr, value):
print "setattr", attr, value
def __delattr__(self, attr):
print "delattr", attr
s = SetattrTest()
s.b = 2
print g.__dict__.items()
print s.__dict__.items()
del s.b
class MappingTest:
def __getitem__(self, key):
......@@ -245,3 +249,29 @@ class E(C, object):
print issubclass(D, C), isinstance(D(), C)
print issubclass(E, C), isinstance(E(), C)
print isinstance(E, object), isinstance(E(), object)
class SeqTest:
class Iterator:
def __init__(self):
self.n = 5
def next(self):
print "next"
if self.n <= 0:
raise StopIteration()
r = self.n
self.n -= 1
return r
def __iter__(self):
print "iter"
return SeqTest.Iterator()
m = SeqTest()
print list(m)
class OldSeqTest:
def __getitem__(self, n):
print "getitem", n
if n > 5:
raise IndexError()
return n ** 2
m = OldSeqTest()
print list(m)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment