Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/capi/abstract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1865,8 +1865,11 @@ extern "C" PyObject* PyNumber_InPlaceOr(PyObject*, PyObject*) noexcept {
return nullptr;
}

extern "C" int PyNumber_Coerce(PyObject**, PyObject**) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
extern "C" int PyNumber_Coerce(PyObject** pv, PyObject** pw) noexcept {
int err = PyNumber_CoerceEx(pv, pw);
if (err <= 0)
return err;
PyErr_SetString(PyExc_TypeError, "number coercion failed");
return -1;
}

Expand Down
16 changes: 14 additions & 2 deletions src/runtime/builtin_modules/builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,18 @@ extern "C" Box* unichr(Box* arg) {
return rtn;
}

Box* coerceFunc(Box* vv, Box* ww) {
Box* res;

if (PyErr_WarnPy3k("coerce() not supported in 3.x", 1) < 0)
throwCAPIException();

if (PyNumber_Coerce(&vv, &ww) < 0)
throwCAPIException();
res = PyTuple_Pack(2, vv, ww);
return res;
}

extern "C" Box* ord(Box* obj) {
long ord;
Py_ssize_t size;
Expand Down Expand Up @@ -1503,10 +1515,10 @@ void setupBuiltins() {
builtins_module->giveAttr(
"reversed",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)getreversed, UNKNOWN, 1, 0, false, false), "reversed"));

builtins_module->giveAttr("coerce", new BoxedBuiltinFunctionOrMethod(
boxRTFunction((void*)coerceFunc, UNKNOWN, 2, 0, false, false), "coerce"));
builtins_module->giveAttr("divmod",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)divmod, UNKNOWN, 2), "divmod"));

builtins_module->giveAttr("execfile",
new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)execfile, UNKNOWN, 1), "execfile"));

Expand Down
180 changes: 180 additions & 0 deletions src/runtime/classobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,76 @@ Box* instanceDelitem(Box* _inst, Box* key) {
return runtimeCall(delitem_func, ArgPassSpec(1), key, NULL, NULL, NULL, NULL);
}

Box* instanceGetslice(Box* _inst, Box* i, Box* j) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* getslice_str = internStringImmortal("__getslice__");
Box* getslice_func = NULL;

try {
getslice_func = _instanceGetattribute(inst, getslice_str, false);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
}

if (getslice_func == NULL) {
Box* slice = static_cast<Box*>(createSlice(i, j, None));
return instanceGetitem(inst, slice);
}

return runtimeCall(getslice_func, ArgPassSpec(2), i, j, NULL, NULL, NULL);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor (not worth changing), but we could have directly copied CPython's instance_slice. It looks like the conversion got rid of some overhead, but I've been liking the approach of starting out with a 100% copy and then optimize as needed.


Box* instanceSetslice(Box* _inst, Box* i, Box* j, Box** sequence) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* setslice_str = internStringImmortal("__setslice__");
Box* setslice_func = NULL;

try {
setslice_func = _instanceGetattribute(inst, setslice_str, false);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
}

if (setslice_func == NULL) {
Box* slice = static_cast<Box*>(createSlice(i, j, None));
return instanceSetitem(inst, slice, *sequence);
}

return runtimeCall(setslice_func, ArgPassSpec(3), i, j, *sequence, NULL, NULL);
}

Box* instanceDelslice(Box* _inst, Box* i, Box* j) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* delslice_str = internStringImmortal("__delslice__");
Box* delslice_func = NULL;

try {
delslice_func = _instanceGetattribute(inst, delslice_str, false);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
}

if (delslice_func == NULL) {
Box* slice = static_cast<Box*>(createSlice(i, j, None));
return instanceDelitem(inst, slice);
}
try {
return runtimeCall(delslice_func, ArgPassSpec(2), i, j, NULL, NULL, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}

/* Try a 3-way comparison, returning an int; v is an instance. Return:
-2 for an exception;
-1 if v < w;
Expand Down Expand Up @@ -1186,6 +1256,101 @@ Box* instanceIor(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, attr_str);
}

Box* instanceNeg(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* neg_str = internStringImmortal("__neg__");
Box* neg_func = _instanceGetattribute(inst, neg_str, true);
return runtimeCall(neg_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instancePos(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* pos_str = internStringImmortal("__pos__");
Box* pos_func = _instanceGetattribute(inst, pos_str, true);
return runtimeCall(pos_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceAbs(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* abs_str = internStringImmortal("__abs__");
Box* abs_func = _instanceGetattribute(inst, abs_str, true);
return runtimeCall(abs_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceInvert(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* invert_str = internStringImmortal("__invert__");
Box* invert_func = _instanceGetattribute(inst, invert_str, true);
return runtimeCall(invert_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceInt(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* int_str = internStringImmortal("__int__");
Box* int_func = _instanceGetattribute(inst, int_str, true);
return runtimeCall(int_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceLong(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* long_str = internStringImmortal("__long__");
Box* long_func = _instanceGetattribute(inst, long_str, true);
return runtimeCall(long_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceFloat(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* float_str = internStringImmortal("__float__");
Box* float_func = _instanceGetattribute(inst, float_str, true);
return runtimeCall(float_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceOct(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* oct_str = internStringImmortal("__oct__");
Box* oct_func = _instanceGetattribute(inst, oct_str, true);
return runtimeCall(oct_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceHex(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* hex_str = internStringImmortal("__hex__");
Box* hex_func = _instanceGetattribute(inst, hex_str, true);
return runtimeCall(hex_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceCoerce(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__coerce__");
return _instanceBinary(_inst, other, attr_str);
}

Box* instanceIndex(Box* _inst) {
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);

static BoxedString* index_str = internStringImmortal("__index__");
Box* index_func = _instanceGetattribute(inst, index_str, true);
return runtimeCall(index_func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}

Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
assert(_inst->cls == instance_cls);
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
Expand Down Expand Up @@ -1284,6 +1449,9 @@ void setupClassobj() {
instance_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)instanceGetitem, UNKNOWN, 2)));
instance_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)instanceSetitem, UNKNOWN, 3)));
instance_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)instanceDelitem, UNKNOWN, 2)));
instance_cls->giveAttr("__getslice__", new BoxedFunction(boxRTFunction((void*)instanceGetslice, UNKNOWN, 3)));
instance_cls->giveAttr("__setslice__", new BoxedFunction(boxRTFunction((void*)instanceSetslice, UNKNOWN, 4)));
instance_cls->giveAttr("__delslice__", new BoxedFunction(boxRTFunction((void*)instanceDelslice, UNKNOWN, 3)));
instance_cls->giveAttr("__cmp__", new BoxedFunction(boxRTFunction((void*)instanceCompare, UNKNOWN, 2)));
instance_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)instanceContains, UNKNOWN, 2)));
instance_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)instanceHash, UNKNOWN, 1)));
Expand Down Expand Up @@ -1341,6 +1509,18 @@ void setupClassobj() {
instance_cls->giveAttr("__ixor__", new BoxedFunction(boxRTFunction((void*)instanceIxor, UNKNOWN, 2)));
instance_cls->giveAttr("__ior__", new BoxedFunction(boxRTFunction((void*)instanceIor, UNKNOWN, 2)));

instance_cls->giveAttr("__neg__", new BoxedFunction(boxRTFunction((void*)instanceNeg, UNKNOWN, 1)));
instance_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)instancePos, UNKNOWN, 1)));
instance_cls->giveAttr("__abs__", new BoxedFunction(boxRTFunction((void*)instanceAbs, UNKNOWN, 1)));
instance_cls->giveAttr("__invert__", new BoxedFunction(boxRTFunction((void*)instanceInvert, UNKNOWN, 1)));
instance_cls->giveAttr("__int__", new BoxedFunction(boxRTFunction((void*)instanceInt, UNKNOWN, 1)));
instance_cls->giveAttr("__long__", new BoxedFunction(boxRTFunction((void*)instanceLong, UNKNOWN, 1)));
instance_cls->giveAttr("__float__", new BoxedFunction(boxRTFunction((void*)instanceFloat, UNKNOWN, 1)));
instance_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)instanceOct, UNKNOWN, 1)));
instance_cls->giveAttr("__hex__", new BoxedFunction(boxRTFunction((void*)instanceHex, UNKNOWN, 1)));
instance_cls->giveAttr("__coerce__", new BoxedFunction(boxRTFunction((void*)instanceCoerce, UNKNOWN, 2)));
instance_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)instanceIndex, UNKNOWN, 1)));

instance_cls->freeze();
instance_cls->tp_getattro = instance_getattro;
instance_cls->tp_setattro = instance_setattro;
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/objmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4713,6 +4713,8 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_
sliceIndex(bslice->stop, &stop);

adjustNegativeIndicesOnObject(target, &start, &stop);
if (PyErr_Occurred())
throwCAPIException();

Box* boxedStart = boxInt(start);
Box* boxedStop = boxInt(stop);
Expand Down
56 changes: 56 additions & 0 deletions test/tests/oldstyle_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,50 @@ def __ne__(self, other):
print "ne"
return self.n != other.n

def __neg__(self):
print "neg"
return -self.n

def __pos__(self):
print "pos"
return +self.n

def __abs__(self):
print "abs"
return abs(self.n)

def __invert__(self):
print "invert"
return ~self.n

def __int__(self):
print "int"
return int(self.n)

def __long__(self):
print "long"
return long(self.n)

def __float__(self):
print "float"
return float(self.n)

def __oct__(self):
print "oct"
return oct(self.n)

def __hex__(self):
print "hex"
return hex(self.n)

def __coerce__(self, other):
print "coerce"
return (int(self.n), other)

def __index__(self):
print "index"
return self.n

e = E(1)
print e
print e.n
Expand All @@ -73,6 +117,18 @@ def __ne__(self, other):
print e()("test")
print e == E(1)
print e != E(1)
print -e
print +e
print abs(e)
print ~e
print int(e)
print long(e)
print float(e)
print oct(e)
print hex(e)
print coerce(e, 10)
test_list = ["abc", "efg", "hij"]
print test_list[e]

def str2():
return "str2"
Expand Down