Commit 9956a566 authored by Marius Wachtler's avatar Marius Wachtler

Add pow(), long.__mod__, __index__, slice and xrange long arg support,

support for 3arg pow, long("0xBB", 16) and long("0xBBL", 0)
parent 56495410
......@@ -1038,6 +1038,149 @@ static PyObject* binary_op(PyObject* v, PyObject* w, const int op_slot, const ch
return result;
}
/*
Calling scheme used for ternary operations:
*** In some cases, w.op is called before v.op; see binary_op1. ***
v w z Action
-------------------------------------------------------------------
new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z)
old old old coerce(v,w,z), v.op(v,w,z)
Legend:
-------
* new == new style number
* old == old style number
* Action indicates the order in which operations are tried until either
a valid result is produced or an error occurs.
* coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and
only if z != Py_None; if z == Py_None, then it is treated as absent
variable and only coerce(v,w) is tried.
*/
static PyObject* ternary_op(PyObject* v, PyObject* w, PyObject* z, const int op_slot, const char* op_name) noexcept {
PyNumberMethods* mv, *mw, *mz;
PyObject* x = NULL;
ternaryfunc slotv = NULL;
ternaryfunc slotw = NULL;
ternaryfunc slotz = NULL;
mv = v->cls->tp_as_number;
mw = w->cls->tp_as_number;
if (mv != NULL && NEW_STYLE_NUMBER(v))
slotv = NB_TERNOP(mv, op_slot);
if (w->cls != v->cls && mw != NULL && NEW_STYLE_NUMBER(w)) {
slotw = NB_TERNOP(mw, op_slot);
if (slotw == slotv)
slotw = NULL;
}
if (slotv) {
if (slotw && PyType_IsSubtype(w->cls, v->cls)) {
x = slotw(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
slotw = NULL;
}
x = slotv(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
if (slotw) {
x = slotw(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
mz = z->cls->tp_as_number;
if (mz != NULL && NEW_STYLE_NUMBER(z)) {
slotz = NB_TERNOP(mz, op_slot);
if (slotz == slotv || slotz == slotw)
slotz = NULL;
if (slotz) {
x = slotz(v, w, z);
if (x != Py_NotImplemented)
return x;
Py_DECREF(x); /* can't do it */
}
}
if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) || (z != Py_None && !NEW_STYLE_NUMBER(z))) {
/* we have an old style operand, coerce */
PyObject* v1, *z1, *w2, *z2;
int c;
c = PyNumber_Coerce(&v, &w);
if (c != 0)
goto error3;
/* Special case: if the third argument is None, it is
treated as absent argument and not coerced. */
if (z == Py_None) {
if (v->cls->tp_as_number) {
slotz = NB_TERNOP(v->cls->tp_as_number, op_slot);
if (slotz)
x = slotz(v, w, z);
else
c = -1;
} else
c = -1;
goto error2;
}
v1 = v;
z1 = z;
c = PyNumber_Coerce(&v1, &z1);
if (c != 0)
goto error2;
w2 = w;
z2 = z1;
c = PyNumber_Coerce(&w2, &z2);
if (c != 0)
goto error1;
if (v1->cls->tp_as_number != NULL) {
slotv = NB_TERNOP(v1->cls->tp_as_number, op_slot);
if (slotv)
x = slotv(v1, w2, z2);
else
c = -1;
} else
c = -1;
Py_DECREF(w2);
Py_DECREF(z2);
error1:
Py_DECREF(v1);
Py_DECREF(z1);
error2:
Py_DECREF(v);
Py_DECREF(w);
error3:
if (c >= 0)
return x;
}
if (z == Py_None)
PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for ** or pow(): "
"'%.100s' and '%.100s'",
v->cls->tp_name, w->cls->tp_name);
else
PyErr_Format(PyExc_TypeError, "unsupported operand type(s) for pow(): "
"'%.100s', '%.100s', '%.100s'",
v->cls->tp_name, w->cls->tp_name, z->cls->tp_name);
return NULL;
}
extern "C" PyObject* PySequence_Concat(PyObject* s, PyObject* o) noexcept {
PySequenceMethods* m;
......@@ -1392,9 +1535,8 @@ extern "C" PyObject* PyNumber_Divmod(PyObject* lhs, PyObject* rhs) noexcept {
}
}
extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_Power(PyObject* v, PyObject* w, PyObject* z) noexcept {
return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
}
extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
......@@ -1421,9 +1563,13 @@ extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
return nullptr;
}
extern "C" PyObject* PyNumber_Lshift(PyObject*, PyObject*) noexcept {
extern "C" PyObject* PyNumber_Lshift(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::LShift);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
}
}
extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
......@@ -1684,8 +1830,21 @@ extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept {
return o;
}
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
if (PyIndex_Check(o)) {
result = o->cls->tp_as_number->nb_index(o);
if (result && !PyInt_Check(result) && !PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError, "__index__ returned non-(int,long) "
"(type %.200s)",
result->cls->tp_name);
Py_DECREF(result);
return NULL;
}
} else {
PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted "
"as an index",
o->cls->tp_name);
}
return result;
}
extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
......@@ -1693,18 +1852,42 @@ extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
return nullptr;
}
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) noexcept {
if (isSubclass(o->cls, int_cls)) {
int64_t n = static_cast<BoxedInt*>(o)->n;
static_assert(sizeof(n) == sizeof(Py_ssize_t), "");
return n;
} else if (isSubclass(o->cls, long_cls)) {
return PyLong_AsSsize_t(o);
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* item, PyObject* err) noexcept {
Py_ssize_t result;
PyObject* runerr;
PyObject* value = PyNumber_Index(item);
if (value == NULL)
return -1;
/* We're done if PyInt_AsSsize_t() returns without error. */
result = PyInt_AsSsize_t(value);
if (result != -1 || !(runerr = PyErr_Occurred()))
goto finish;
/* Error handling code -- only manage OverflowError differently */
if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
goto finish;
PyErr_Clear();
/* If no error-handling desired then the default clipping
is sufficient.
*/
if (!err) {
assert(PyLong_Check(value));
/* Whether or not it is less than or equal to
zero is determined by the sign of ob_size
*/
if (_PyLong_Sign(value) < 0)
result = PY_SSIZE_T_MIN;
else
result = PY_SSIZE_T_MAX;
} else {
/* Otherwise replace the error with caller's error object. */
PyErr_Format(err, "cannot fit '%.200s' into an index-sized integer", item->cls->tp_name);
}
PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted "
"as an index",
o->cls->tp_name);
return -1;
finish:
Py_DECREF(value);
return result;
}
}
......@@ -750,6 +750,12 @@ Box* divmod(Box* lhs, Box* rhs) {
return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL);
}
Box* powFunc(Box* x, Box* y, Box* z) {
Box* rtn = PyNumber_Power(x, y, z);
checkAndThrowCAPIException();
return rtn;
}
Box* execfile(Box* _fn) {
// The "globals" and "locals" arguments aren't implemented for now
if (!isSubclass(_fn->cls, str_cls)) {
......@@ -1082,6 +1088,8 @@ void setupBuiltins() {
Box* hasattr_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)hasattr, BOXED_BOOL, 2), "hasattr");
builtins_module->giveAttr("hasattr", hasattr_obj);
builtins_module->giveAttr("pow", new BoxedBuiltinFunctionOrMethod(
boxRTFunction((void*)powFunc, UNKNOWN, 3, 1, false, false), "pow", { None }));
Box* isinstance_obj
= new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)isinstance_func, BOXED_BOOL, 2), "isinstance");
......
......@@ -38,9 +38,9 @@ namespace pyston {
BoxedClass* method_cls;
extern "C" bool _PyIndex_Check(PyObject* op) noexcept {
// TODO this is wrong (the CPython version checks for things that can be coerced to a number):
return PyInt_Check(op);
extern "C" bool _PyIndex_Check(PyObject* obj) noexcept {
return (Py_TYPE(obj)->tp_as_number != NULL && PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HAVE_INDEX)
&& Py_TYPE(obj)->tp_as_number->nb_index != NULL);
}
extern "C" bool _PyObject_CheckBuffer(PyObject* obj) noexcept {
......
......@@ -488,6 +488,29 @@ static Box* instanceHash(BoxedInstance* inst) {
}
}
static PyObject* instance_index(PyObject* self) noexcept {
PyObject* func, *res;
/*
static PyObject* indexstr = NULL;
if (indexstr == NULL) {
indexstr = PyString_InternFromString("__index__");
if (indexstr == NULL)
return NULL;
}
*/
if ((func = instance_getattro(self, boxString("__index__"))) == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
PyErr_SetString(PyExc_TypeError, "object cannot be interpreted as an index");
return NULL;
}
res = PyEval_CallObject(func, (PyObject*)NULL);
Py_DECREF(func);
return res;
}
Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
assert(_inst->cls == instance_cls);
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -541,5 +564,6 @@ void setupClassobj() {
instance_cls->freeze();
instance_cls->tp_getattro = instance_getattro;
instance_cls->tp_setattro = instance_setattro;
instance_cls->tp_as_number->nb_index = instance_index;
}
}
......@@ -390,20 +390,27 @@ extern "C" Box* floatRMod(BoxedFloat* lhs, Box* rhs) {
}
}
extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs) {
extern "C" Box* floatPowFloat(BoxedFloat* lhs, BoxedFloat* rhs, Box* mod = None) {
assert(lhs->cls == float_cls);
assert(rhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->d));
}
extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs) {
extern "C" Box* floatPowInt(BoxedFloat* lhs, BoxedInt* rhs, Box* mod = None) {
assert(lhs->cls == float_cls);
assert(isSubclass(rhs->cls, int_cls));
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
return boxFloat(pow(lhs->d, rhs->n));
}
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs) {
extern "C" Box* floatPow(BoxedFloat* lhs, Box* rhs, Box* mod) {
assert(lhs->cls == float_cls);
if (mod != None)
raiseExcHelper(TypeError, "pow() 3rd argument not allowed unless all arguments are integers");
if (isSubclass(rhs->cls, int_cls)) {
return floatPowInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) {
......@@ -708,6 +715,19 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* flo
float_cls->giveAttr(name, new BoxedFunction(cl));
}
static void _addFuncPow(const char* name, ConcreteCompilerType* rtn_type, void* float_func, void* int_func,
void* boxed_func) {
std::vector<ConcreteCompilerType*> v_ffu{ BOXED_FLOAT, BOXED_FLOAT, UNKNOWN };
std::vector<ConcreteCompilerType*> v_fiu{ BOXED_FLOAT, BOXED_INT, UNKNOWN };
std::vector<ConcreteCompilerType*> v_fuu{ BOXED_FLOAT, UNKNOWN, UNKNOWN };
CLFunction* cl = createRTFunction(3, 1, false, false);
addRTFunction(cl, float_func, rtn_type, v_ffu);
addRTFunction(cl, int_func, rtn_type, v_fiu);
addRTFunction(cl, boxed_func, UNKNOWN, v_fuu);
float_cls->giveAttr(name, new BoxedFunction(cl, { None }));
}
void setupFloat() {
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr("__add__"));
......@@ -729,7 +749,7 @@ void setupFloat() {
_addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul);
float_cls->giveAttr("__rmul__", float_cls->getattr("__mul__"));
_addFunc("__pow__", BOXED_FLOAT, (void*)floatPowFloat, (void*)floatPowInt, (void*)floatPow);
_addFuncPow("__pow__", BOXED_FLOAT, (void*)floatPowFloat, (void*)floatPowInt, (void*)floatPow);
_addFunc("__sub__", BOXED_FLOAT, (void*)floatSubFloat, (void*)floatSubInt, (void*)floatSub);
_addFunc("__rsub__", BOXED_FLOAT, (void*)floatRSubFloat, (void*)floatRSubInt, (void*)floatRSub);
......
......@@ -13,6 +13,7 @@
// limitations under the License.
#include "core/types.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......@@ -134,25 +135,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) {
Box* step = args[0];
if (stop == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start));
i64 istop = static_cast<BoxedInt*>(start)->n;
i64 istop = PyLong_AsLong(start);
checkAndThrowCAPIException();
return new BoxedXrange(0, istop, 1);
} else if (step == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start));
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop));
i64 istart = static_cast<BoxedInt*>(start)->n;
i64 istop = static_cast<BoxedInt*>(stop)->n;
i64 istart = PyLong_AsLong(start);
checkAndThrowCAPIException();
i64 istop = PyLong_AsLong(stop);
checkAndThrowCAPIException();
return new BoxedXrange(istart, istop, 1);
} else {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start));
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop));
RELEASE_ASSERT(isSubclass(step->cls, int_cls), "%s", getTypeName(step));
i64 istart = static_cast<BoxedInt*>(start)->n;
i64 istop = static_cast<BoxedInt*>(stop)->n;
i64 istep = static_cast<BoxedInt*>(step)->n;
i64 istart = PyLong_AsLong(start);
checkAndThrowCAPIException();
i64 istop = PyLong_AsLong(stop);
checkAndThrowCAPIException();
i64 istep = PyLong_AsLong(step);
checkAndThrowCAPIException();
RELEASE_ASSERT(istep != 0, "step can't be 0");
return new BoxedXrange(istart, istop, istep);
}
......
......@@ -58,8 +58,20 @@ extern "C" long PyInt_AsLong(PyObject* op) noexcept {
}
extern "C" Py_ssize_t PyInt_AsSsize_t(PyObject* op) noexcept {
RELEASE_ASSERT(isSubclass(op->cls, int_cls), "");
return static_cast<BoxedInt*>(op)->n;
if (op == NULL) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
return -1;
}
if (PyInt_Check(op))
return ((BoxedInt*)op)->n;
if (PyLong_Check(op))
return _PyLong_AsSsize_t(op);
#if SIZEOF_SIZE_T == SIZEOF_LONG
return PyInt_AsLong(op);
#else
RELEASE_ASSERT("not implemented", "");
#endif
}
extern "C" PyObject* PyInt_FromSize_t(size_t ival) noexcept {
......@@ -758,14 +770,18 @@ extern "C" Box* intPowFloat(BoxedInt* lhs, BoxedFloat* rhs) {
return boxFloat(pow(lhs->n, rhs->d));
}
extern "C" Box* intPow(BoxedInt* lhs, Box* rhs) {
extern "C" Box* intPow(BoxedInt* lhs, Box* rhs, Box* mod) {
if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (isSubclass(rhs->cls, int_cls)) {
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs);
return intPowInt(lhs, rhs_int);
Box* rtn = intPowInt(lhs, rhs_int);
if (mod == None)
return rtn;
return binop(rtn, mod, AST_TYPE::Mod);
} else if (rhs->cls == float_cls) {
RELEASE_ASSERT(mod == None, "");
BoxedFloat* rhs_float = static_cast<BoxedFloat*>(rhs);
return intPowFloat(lhs, rhs_float);
} else {
......@@ -924,6 +940,12 @@ extern "C" Box* intTrunc(BoxedInt* self) {
return self;
}
extern "C" Box* intIndex(BoxedInt* v) {
if (PyInt_CheckExact(v))
return v;
return boxInt(v->n);
}
static Box* _intNew(Box* val, Box* base) {
if (isSubclass(val->cls, int_cls)) {
RELEASE_ASSERT(!base, "");
......@@ -1057,7 +1079,8 @@ void setupInt() {
_addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intTruedivFloat, (void*)intTruediv);
_addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul);
_addFuncIntUnknown("__mod__", BOXED_INT, (void*)intModInt, (void*)intMod);
_addFuncIntFloatUnknown("__pow__", (void*)intPowInt, (void*)intPowFloat, (void*)intPow);
int_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)intPow, UNKNOWN, 3, 1, false, false), { None }));
_addFuncIntUnknown("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq);
_addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe);
......@@ -1081,6 +1104,7 @@ void setupInt() {
int_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)intOct, STR, 1)));
int_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)intTrunc, BOXED_INT, 1)));
int_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)intIndex, BOXED_INT, 1)));
int_cls->giveAttr(
"__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL }));
......
......@@ -192,8 +192,11 @@ extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) {
extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) {
return listGetitemInt(self, static_cast<BoxedInt*>(slice));
if (PyIndex_Check(slice)) {
Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
return listGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice));
} else {
......@@ -212,23 +215,23 @@ static void _listSetitem(BoxedList* self, int64_t n, Box* v) {
self->elts->elts[n] = v;
}
extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
extern "C" Box* listSetitemUnboxed(BoxedList* self, int64_t n, Box* v) {
// I think r lock is ok here, since we don't change the list structure:
LOCK_REGION(self->lock.asRead());
assert(isSubclass(self->cls, list_cls));
assert(isSubclass(slice->cls, int_cls));
int64_t n = slice->n;
_listSetitem(self, n, v);
return None;
}
extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
assert(isSubclass(slice->cls, int_cls));
return listSetitemUnboxed(self, slice->n, v);
}
extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept {
assert(isSubclass(op->cls, list_cls));
try {
_listSetitem(static_cast<BoxedList*>(op), i, newitem);
listSetitemUnboxed(static_cast<BoxedList*>(op), i, newitem);
} catch (ExcInfo e) {
abort();
}
......@@ -460,8 +463,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) {
return listSetitemInt(self, static_cast<BoxedInt*>(slice), v);
if (PyIndex_Check(slice)) {
Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
listSetitemUnboxed(self, i, v);
return None;
} else if (slice->cls == slice_cls) {
return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v);
} else {
......@@ -492,9 +499,11 @@ extern "C" Box* listDelitem(BoxedList* self, Box* slice) {
LOCK_REGION(self->lock.asWrite());
Box* rtn;
if (isSubclass(slice->cls, int_cls)) {
rtn = listDelitemInt(self, static_cast<BoxedInt*>(slice));
if (PyIndex_Check(slice)) {
Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
rtn = listDelitemInt(self, (BoxedInt*)boxInt(i));
} else if (slice->cls == slice_cls) {
rtn = listDelitemSlice(self, static_cast<BoxedSlice*>(slice));
} else {
......
......@@ -25,6 +25,7 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/inline/boxing.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
......@@ -104,12 +105,58 @@ extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflo
extern "C" PyObject* PyLong_FromString(const char* str, char** pend, int base) noexcept {
RELEASE_ASSERT(pend == NULL, "unsupported");
// See comment in _longNew
RELEASE_ASSERT(base >= 0, "unsupported");
int sign = 1;
if ((base != 0 && base < 2) || base > 36) {
PyErr_SetString(PyExc_ValueError, "long() arg 2 must be >= 2 and <= 36");
return NULL;
}
while (*str != '\0' && isspace(Py_CHARMASK(*str)))
str++;
if (*str == '+')
++str;
else if (*str == '-') {
++str;
sign = -1;
}
while (*str != '\0' && isspace(Py_CHARMASK(*str)))
str++;
if (base == 0) {
/* No base given. Deduce the base from the contents
of the string */
if (str[0] != '0')
base = 10;
else if (str[1] == 'x' || str[1] == 'X')
base = 16;
else if (str[1] == 'o' || str[1] == 'O')
base = 8;
else if (str[1] == 'b' || str[1] == 'B')
base = 2;
else
/* "old" (C-style) octal literal, still valid in
2.x, although illegal in 3.x */
base = 8;
}
/* Whether or not we were deducing the base, skip leading chars
as needed */
if (str[0] == '0'
&& ((base == 16 && (str[1] == 'x' || str[1] == 'X')) || (base == 8 && (str[1] == 'o' || str[1] == 'O'))
|| (base == 2 && (str[1] == 'b' || str[1] == 'B'))))
str += 2;
BoxedLong* rtn = new BoxedLong();
if (str[strlen(str) - 1] == 'L') {
std::string without_l(str, strlen(str) - 1);
int r = mpz_init_set_str(rtn->n, without_l.c_str(), base);
RELEASE_ASSERT(r == 0, "");
} else {
int r = mpz_init_set_str(rtn->n, str, base);
RELEASE_ASSERT(r == 0, "");
}
if (sign == -1)
mpz_neg(rtn->n, rtn->n);
return rtn;
}
......@@ -441,18 +488,8 @@ BoxedLong* _longNew(Box* val, Box* _base) {
raiseExcHelper(TypeError, "long() can't convert non-string with explicit base");
BoxedString* s = static_cast<BoxedString*>(val);
if (base == 0) {
// mpz_init_set_str has the ability to auto-detect the base, but I doubt it's
// quite the same as Python's (ex might be missing octal or binary)
Py_FatalError("unimplemented");
}
if (base < 2 || base > 36) {
raiseExcHelper(TypeError, "long() arg2 must be >= 2 and <= 36");
}
int r = mpz_init_set_str(rtn->n, s->data(), base);
RELEASE_ASSERT(r == 0, "");
rtn = (BoxedLong*)PyLong_FromString(s->s.str().c_str(), NULL, base);
checkAndThrowCAPIException();
} else {
if (isSubclass(val->cls, long_cls)) {
BoxedLong* l = static_cast<BoxedLong*>(val);
......@@ -920,6 +957,51 @@ Box* longDiv(BoxedLong* v1, Box* _v2) {
}
}
Box* longMod(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__mod__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
if (mpz_cmp_si(v2->n, 0) == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_mmod(r->n, v1->n, v2->n);
return r;
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
if (v2->n == 0)
raiseExcHelper(ZeroDivisionError, "long division or modulo by zero");
BoxedLong* r = new BoxedLong();
mpz_init_set_si(r->n, v2->n);
mpz_mmod(r->n, v1->n, r->n);
return r;
} else {
return NotImplemented;
}
}
Box* longRMod(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__rmod__' requires a 'long' object but received a '%s'",
getTypeName(v1));
Box* lhs = _v2;
BoxedLong* rhs = v1;
if (isSubclass(lhs->cls, long_cls)) {
return longMod((BoxedLong*)lhs, rhs);
} else if (isSubclass(lhs->cls, int_cls)) {
return longMod(boxLong(((BoxedInt*)lhs)->n), rhs);
} else {
return NotImplemented;
}
}
extern "C" Box* longDivmod(BoxedLong* lhs, Box* _rhs) {
if (!isSubclass(lhs->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'",
......@@ -1018,26 +1100,44 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) {
return boxFloat(lhs / (double)rhs);
}
Box* longPow(BoxedLong* v1, Box* _v2) {
Box* longPow(BoxedLong* v1, Box* _v2, Box* _v3) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'", getTypeName(v1));
BoxedLong* mod = nullptr;
if (_v3 != None) {
if (isSubclass(_v3->cls, int_cls))
mod = boxLong(((BoxedInt*)_v3)->n);
else {
RELEASE_ASSERT(_v3->cls == long_cls, "");
mod = (BoxedLong*)_v3;
}
RELEASE_ASSERT(mpz_sgn(mod->n) >= 0, "");
}
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
RELEASE_ASSERT(mpz_sgn(v2->n) >= 0, "");
if (mod) {
mpz_powm(r->n, v1->n, v2->n, mod->n);
} else {
RELEASE_ASSERT(mpz_fits_ulong_p(v2->n), "");
uint64_t n2 = mpz_get_ui(v2->n);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_pow_ui(r->n, v1->n, n2);
}
return r;
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
RELEASE_ASSERT(v2->n >= 0, "");
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
if (mod)
mpz_powm_ui(r->n, v1->n, v2->n, mod->n);
else
mpz_pow_ui(r->n, v1->n, v2->n);
return r;
} else {
......@@ -1101,6 +1201,53 @@ void customised_free(void* ptr, size_t size) {
gc::gc_free(ptr);
}
extern "C" Box* longIndex(BoxedLong* v) noexcept {
if (PyLong_CheckExact(v))
return v;
BoxedLong* rtn = new BoxedLong();
mpz_init_set(rtn->n, v->n);
return rtn;
}
static int convert_binop(PyObject* v, PyObject* w, PyLongObject** a, PyLongObject** b) noexcept {
if (PyLong_Check(v)) {
*a = (PyLongObject*)v;
Py_INCREF(v);
} else if (PyInt_Check(v)) {
*a = (PyLongObject*)PyLong_FromLong(PyInt_AS_LONG(v));
} else {
return 0;
}
if (PyLong_Check(w)) {
*b = (PyLongObject*)w;
Py_INCREF(w);
} else if (PyInt_Check(w)) {
*b = (PyLongObject*)PyLong_FromLong(PyInt_AS_LONG(w));
} else {
Py_DECREF(*a);
return 0;
}
return 1;
}
#define CONVERT_BINOP(v, w, a, b) \
do { \
if (!convert_binop(v, w, a, b)) { \
Py_INCREF(Py_NotImplemented); \
return Py_NotImplemented; \
} \
} while (0)
static PyObject* long_pow(PyObject* v, PyObject* w, PyObject* x) noexcept {
try {
PyLongObject* a, *b;
CONVERT_BINOP(v, w, &a, &b);
return longPow((BoxedLong*)a, (BoxedLong*)b, x);
} catch (ExcInfo e) {
abort();
}
}
void setupLong() {
mp_set_memory_functions(customised_allocation, customised_realloc, customised_free);
......@@ -1114,6 +1261,8 @@ void setupLong() {
long_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)longRdiv, UNKNOWN, 2)));
long_cls->giveAttr("__truediv__", new BoxedFunction(boxRTFunction((void*)longTrueDiv, UNKNOWN, 2)));
long_cls->giveAttr("__rtruediv__", new BoxedFunction(boxRTFunction((void*)longRTrueDiv, UNKNOWN, 2)));
long_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)longMod, UNKNOWN, 2)));
long_cls->giveAttr("__rmod__", new BoxedFunction(boxRTFunction((void*)longRMod, UNKNOWN, 2)));
long_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)longDivmod, UNKNOWN, 2)));
......@@ -1123,7 +1272,8 @@ void setupLong() {
long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2)));
long_cls->giveAttr("__radd__", long_cls->getattr("__add__"));
long_cls->giveAttr("__pow__", new BoxedFunction(boxRTFunction((void*)longPow, UNKNOWN, 2)));
long_cls->giveAttr("__pow__",
new BoxedFunction(boxRTFunction((void*)longPow, UNKNOWN, 3, 1, false, false), { None }));
long_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2)));
long_cls->giveAttr("__rand__", long_cls->getattr("__and__"));
......@@ -1154,7 +1304,10 @@ void setupLong() {
long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1)));
long_cls->giveAttr("__trunc__", new BoxedFunction(boxRTFunction((void*)longTrunc, UNKNOWN, 1)));
long_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)longIndex, LONG, 1)));
long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow;
}
}
......@@ -47,7 +47,7 @@ Box* longAdd(BoxedLong* lhs, Box* rhs);
Box* longSub(BoxedLong* lhs, Box* rhs);
Box* longMul(BoxedLong* lhs, Box* rhs);
Box* longDiv(BoxedLong* lhs, Box* rhs);
Box* longPow(BoxedLong* lhs, Box* rhs);
Box* longPow(BoxedLong* lhs, Box* rhs, Box* mod = None);
Box* longLshift(BoxedLong* lhs, Box* rhs);
Box* longRshift(BoxedLong* lhs, Box* rhs);
......
......@@ -326,6 +326,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
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;
......
......@@ -2240,9 +2240,10 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
assert(isSubclass(self->cls, str_cls));
if (isSubclass(slice->cls, int_cls)) {
BoxedInt* islice = static_cast<BoxedInt*>(slice);
int64_t n = islice->n;
if (PyIndex_Check(slice)) {
Py_ssize_t n = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (n == -1 && PyErr_Occurred())
throwCAPIException();
int size = self->size();
if (n < 0)
n = size + n;
......
......@@ -23,6 +23,7 @@
#include "core/stats.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -146,9 +147,12 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept {
Box* tupleGetitem(BoxedTuple* self, Box* slice) {
assert(self->cls == tuple_cls);
if (isSubclass(slice->cls, int_cls))
return tupleGetitemInt(self, static_cast<BoxedInt*>(slice));
else if (slice->cls == slice_cls)
if (PyIndex_Check(slice)) {
Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
throwCAPIException();
return tupleGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls)
return tupleGetitemSlice(self, static_cast<BoxedSlice*>(slice));
else
raiseExcHelper(TypeError, "tuple indices must be integers, not %s", getTypeName(slice));
......
......@@ -40,6 +40,8 @@ print isinstance(1, int)
print isinstance(1, (float, int))
print isinstance(1, (float, (), (int, 3), 4))
print pow(11, 42)
print pow(11, 42, 75)
print divmod(5, 2)
print divmod(5L, -2)
try:
......
# expected: fail
# - long % int
import sys
P = 1000000007
......
class Index(object):
def __init__(self, i):
self.i = i
def __index__(self):
print "called __index__"
return self.i
s = "String"
l = [1, 2, "List"]
t = (1, 2, "Tuple")
print s[Index(2L)]
print l[Index(2L)]
print t[Index(2L)]
......@@ -13,6 +13,9 @@ for i in xrange(1, 12):
print 1 ** 0
print 0 ** 0
print -1 ** 0
print (11).__pow__(5, 50)
print (11).__pow__(32, 50)
print (11).__index__()
for i in (-10, 10, 0, -15):
print i, i.__hex__(), i.__oct__()
......
......@@ -4,6 +4,7 @@ print l * 5
l[0] = 1
print l
print l[2]
print l[2L]
l = range(5)
while l:
......
......@@ -13,6 +13,7 @@ def test(a, b):
print a - b, b - a, a.__sub__(b), b.__sub__(a)
print a * b, b * a, a.__mul__(b), b.__mul__(a)
print a / b, b / a, a.__div__(b), b.__div__(a)
print a % b, b % a, a.__mod__(b), b.__mod__(a)
print repr(a), repr(b), a < b, a > b, a <= b, a >= b, a == b, a != b
if not isinstance(a, float) and not isinstance(b, float):
print a ^ b, a | b, a & b
......@@ -55,10 +56,15 @@ print ~(-10L)
print -(1L)
print 1L**2L
print 1L**2
print (11L).__pow__(32, 50L)
print (11L).__index__()
print long("100", 16)
print long("100", 10)
print long("100", 26)
print long("0x100", 16), long("0100", 8), long("0b100", 2)
print long("0x100", 0), long("0100", 0), long("0b100", 0)
print long("0b100", 16), long("0b100L", 0), long("-0b100L", 0)
print long(-1.1)
print long(1.9)
print long(-1.9)
......
......@@ -133,6 +133,7 @@ except TypeError, e:
t = (1, "2")
print t[0]
print t[1]
print t[1L]
t = (1, 2, 'a', 'b', 'c')
print t[::-1]
......
......@@ -15,3 +15,6 @@ for i in xrange(10, -10, -3):
for i in xrange(0):
print i
for i in xrange(10L, 15L, 1L):
print i
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