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 ...@@ -1038,6 +1038,149 @@ static PyObject* binary_op(PyObject* v, PyObject* w, const int op_slot, const ch
return result; 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 { extern "C" PyObject* PySequence_Concat(PyObject* s, PyObject* o) noexcept {
PySequenceMethods* m; PySequenceMethods* m;
...@@ -1392,9 +1535,8 @@ extern "C" PyObject* PyNumber_Divmod(PyObject* lhs, PyObject* rhs) noexcept { ...@@ -1392,9 +1535,8 @@ extern "C" PyObject* PyNumber_Divmod(PyObject* lhs, PyObject* rhs) noexcept {
} }
} }
extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) noexcept { extern "C" PyObject* PyNumber_Power(PyObject* v, PyObject* w, PyObject* z) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented"); return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()");
return nullptr;
} }
extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept { extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
...@@ -1421,9 +1563,13 @@ extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept { ...@@ -1421,9 +1563,13 @@ extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
return nullptr; 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"); fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr; return nullptr;
}
} }
extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept { extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
...@@ -1684,8 +1830,21 @@ extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept { ...@@ -1684,8 +1830,21 @@ extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept {
return o; return o;
} }
fatalOrError(PyExc_NotImplementedError, "unimplemented"); if (PyIndex_Check(o)) {
return nullptr; 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 { extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
...@@ -1693,18 +1852,42 @@ 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; return nullptr;
} }
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) noexcept { extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* item, PyObject* err) noexcept {
if (isSubclass(o->cls, int_cls)) { Py_ssize_t result;
int64_t n = static_cast<BoxedInt*>(o)->n; PyObject* runerr;
static_assert(sizeof(n) == sizeof(Py_ssize_t), ""); PyObject* value = PyNumber_Index(item);
return n; if (value == NULL)
} else if (isSubclass(o->cls, long_cls)) { return -1;
return PyLong_AsSsize_t(o);
/* 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 " finish:
"as an index", Py_DECREF(value);
o->cls->tp_name); return result;
return -1;
} }
} }
...@@ -750,6 +750,12 @@ Box* divmod(Box* lhs, Box* rhs) { ...@@ -750,6 +750,12 @@ Box* divmod(Box* lhs, Box* rhs) {
return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL); 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) { Box* execfile(Box* _fn) {
// The "globals" and "locals" arguments aren't implemented for now // The "globals" and "locals" arguments aren't implemented for now
if (!isSubclass(_fn->cls, str_cls)) { if (!isSubclass(_fn->cls, str_cls)) {
...@@ -1082,6 +1088,8 @@ void setupBuiltins() { ...@@ -1082,6 +1088,8 @@ void setupBuiltins() {
Box* hasattr_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)hasattr, BOXED_BOOL, 2), "hasattr"); Box* hasattr_obj = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)hasattr, BOXED_BOOL, 2), "hasattr");
builtins_module->giveAttr("hasattr", hasattr_obj); 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 Box* isinstance_obj
= new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)isinstance_func, BOXED_BOOL, 2), "isinstance"); = new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)isinstance_func, BOXED_BOOL, 2), "isinstance");
......
...@@ -38,9 +38,9 @@ namespace pyston { ...@@ -38,9 +38,9 @@ namespace pyston {
BoxedClass* method_cls; BoxedClass* method_cls;
extern "C" bool _PyIndex_Check(PyObject* op) noexcept { extern "C" bool _PyIndex_Check(PyObject* obj) noexcept {
// TODO this is wrong (the CPython version checks for things that can be coerced to a number): return (Py_TYPE(obj)->tp_as_number != NULL && PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HAVE_INDEX)
return PyInt_Check(op); && Py_TYPE(obj)->tp_as_number->nb_index != NULL);
} }
extern "C" bool _PyObject_CheckBuffer(PyObject* obj) noexcept { extern "C" bool _PyObject_CheckBuffer(PyObject* obj) noexcept {
......
...@@ -488,6 +488,29 @@ static Box* instanceHash(BoxedInstance* inst) { ...@@ -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) { Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
assert(_inst->cls == instance_cls); assert(_inst->cls == instance_cls);
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -541,5 +564,6 @@ void setupClassobj() { ...@@ -541,5 +564,6 @@ void setupClassobj() {
instance_cls->freeze(); instance_cls->freeze();
instance_cls->tp_getattro = instance_getattro; instance_cls->tp_getattro = instance_getattro;
instance_cls->tp_setattro = instance_setattro; 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) { ...@@ -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(lhs->cls == float_cls);
assert(rhs->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)); 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(lhs->cls == float_cls);
assert(isSubclass(rhs->cls, int_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)); 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); 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)) { if (isSubclass(rhs->cls, int_cls)) {
return floatPowInt(lhs, static_cast<BoxedInt*>(rhs)); return floatPowInt(lhs, static_cast<BoxedInt*>(rhs));
} else if (rhs->cls == float_cls) { } else if (rhs->cls == float_cls) {
...@@ -708,6 +715,19 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* flo ...@@ -708,6 +715,19 @@ static void _addFunc(const char* name, ConcreteCompilerType* rtn_type, void* flo
float_cls->giveAttr(name, new BoxedFunction(cl)); 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() { void setupFloat() {
_addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd); _addFunc("__add__", BOXED_FLOAT, (void*)floatAddFloat, (void*)floatAddInt, (void*)floatAdd);
float_cls->giveAttr("__radd__", float_cls->getattr("__add__")); float_cls->giveAttr("__radd__", float_cls->getattr("__add__"));
...@@ -729,7 +749,7 @@ void setupFloat() { ...@@ -729,7 +749,7 @@ void setupFloat() {
_addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul); _addFunc("__mul__", BOXED_FLOAT, (void*)floatMulFloat, (void*)floatMulInt, (void*)floatMul);
float_cls->giveAttr("__rmul__", float_cls->getattr("__mul__")); 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("__sub__", BOXED_FLOAT, (void*)floatSubFloat, (void*)floatSubInt, (void*)floatSub);
_addFunc("__rsub__", BOXED_FLOAT, (void*)floatRSubFloat, (void*)floatRSubInt, (void*)floatRSub); _addFunc("__rsub__", BOXED_FLOAT, (void*)floatRSubFloat, (void*)floatRSubInt, (void*)floatRSub);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "core/types.h" #include "core/types.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -134,25 +135,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) { ...@@ -134,25 +135,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) {
Box* step = args[0]; Box* step = args[0];
if (stop == NULL) { if (stop == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istop = PyLong_AsLong(start);
checkAndThrowCAPIException();
i64 istop = static_cast<BoxedInt*>(start)->n;
return new BoxedXrange(0, istop, 1); return new BoxedXrange(0, istop, 1);
} else if (step == NULL) { } else if (step == NULL) {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istart = PyLong_AsLong(start);
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop)); checkAndThrowCAPIException();
i64 istop = PyLong_AsLong(stop);
i64 istart = static_cast<BoxedInt*>(start)->n; checkAndThrowCAPIException();
i64 istop = static_cast<BoxedInt*>(stop)->n;
return new BoxedXrange(istart, istop, 1); return new BoxedXrange(istart, istop, 1);
} else { } else {
RELEASE_ASSERT(isSubclass(start->cls, int_cls), "%s", getTypeName(start)); i64 istart = PyLong_AsLong(start);
RELEASE_ASSERT(isSubclass(stop->cls, int_cls), "%s", getTypeName(stop)); checkAndThrowCAPIException();
RELEASE_ASSERT(isSubclass(step->cls, int_cls), "%s", getTypeName(step)); i64 istop = PyLong_AsLong(stop);
checkAndThrowCAPIException();
i64 istart = static_cast<BoxedInt*>(start)->n; i64 istep = PyLong_AsLong(step);
i64 istop = static_cast<BoxedInt*>(stop)->n; checkAndThrowCAPIException();
i64 istep = static_cast<BoxedInt*>(step)->n;
RELEASE_ASSERT(istep != 0, "step can't be 0"); RELEASE_ASSERT(istep != 0, "step can't be 0");
return new BoxedXrange(istart, istop, istep); return new BoxedXrange(istart, istop, istep);
} }
......
...@@ -58,8 +58,20 @@ extern "C" long PyInt_AsLong(PyObject* op) noexcept { ...@@ -58,8 +58,20 @@ extern "C" long PyInt_AsLong(PyObject* op) noexcept {
} }
extern "C" Py_ssize_t PyInt_AsSsize_t(PyObject* op) noexcept { extern "C" Py_ssize_t PyInt_AsSsize_t(PyObject* op) noexcept {
RELEASE_ASSERT(isSubclass(op->cls, int_cls), ""); if (op == NULL) {
return static_cast<BoxedInt*>(op)->n; 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 { extern "C" PyObject* PyInt_FromSize_t(size_t ival) noexcept {
...@@ -758,14 +770,18 @@ extern "C" Box* intPowFloat(BoxedInt* lhs, BoxedFloat* rhs) { ...@@ -758,14 +770,18 @@ extern "C" Box* intPowFloat(BoxedInt* lhs, BoxedFloat* rhs) {
return boxFloat(pow(lhs->n, rhs->d)); 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)) if (!isSubclass(lhs->cls, int_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'int' object but received a '%s'", getTypeName(lhs)); raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'int' object but received a '%s'", getTypeName(lhs));
if (isSubclass(rhs->cls, int_cls)) { if (isSubclass(rhs->cls, int_cls)) {
BoxedInt* rhs_int = static_cast<BoxedInt*>(rhs); 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) { } else if (rhs->cls == float_cls) {
RELEASE_ASSERT(mod == None, "");
BoxedFloat* rhs_float = static_cast<BoxedFloat*>(rhs); BoxedFloat* rhs_float = static_cast<BoxedFloat*>(rhs);
return intPowFloat(lhs, rhs_float); return intPowFloat(lhs, rhs_float);
} else { } else {
...@@ -924,6 +940,12 @@ extern "C" Box* intTrunc(BoxedInt* self) { ...@@ -924,6 +940,12 @@ extern "C" Box* intTrunc(BoxedInt* self) {
return 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) { static Box* _intNew(Box* val, Box* base) {
if (isSubclass(val->cls, int_cls)) { if (isSubclass(val->cls, int_cls)) {
RELEASE_ASSERT(!base, ""); RELEASE_ASSERT(!base, "");
...@@ -1057,7 +1079,8 @@ void setupInt() { ...@@ -1057,7 +1079,8 @@ void setupInt() {
_addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intTruedivFloat, (void*)intTruediv); _addFuncIntFloatUnknown("__truediv__", (void*)intTruedivInt, (void*)intTruedivFloat, (void*)intTruediv);
_addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul); _addFuncIntFloatUnknown("__mul__", (void*)intMulInt, (void*)intMulFloat, (void*)intMul);
_addFuncIntUnknown("__mod__", BOXED_INT, (void*)intModInt, (void*)intMod); _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("__eq__", BOXED_BOOL, (void*)intEqInt, (void*)intEq);
_addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe); _addFuncIntUnknown("__ne__", BOXED_BOOL, (void*)intNeInt, (void*)intNe);
...@@ -1081,6 +1104,7 @@ void setupInt() { ...@@ -1081,6 +1104,7 @@ void setupInt() {
int_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)intOct, STR, 1))); 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("__trunc__", new BoxedFunction(boxRTFunction((void*)intTrunc, BOXED_INT, 1)));
int_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)intIndex, BOXED_INT, 1)));
int_cls->giveAttr( int_cls->giveAttr(
"__new__", new BoxedFunction(boxRTFunction((void*)intNew, UNKNOWN, 3, 2, false, false), { boxInt(0), NULL })); "__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) { ...@@ -192,8 +192,11 @@ extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) {
extern "C" Box* listGetitem(BoxedList* self, Box* slice) { extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
return listGetitemInt(self, static_cast<BoxedInt*>(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) { } else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice)); return listGetitemSlice(self, static_cast<BoxedSlice*>(slice));
} else { } else {
...@@ -212,23 +215,23 @@ static void _listSetitem(BoxedList* self, int64_t n, Box* v) { ...@@ -212,23 +215,23 @@ static void _listSetitem(BoxedList* self, int64_t n, Box* v) {
self->elts->elts[n] = 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: // I think r lock is ok here, since we don't change the list structure:
LOCK_REGION(self->lock.asRead()); LOCK_REGION(self->lock.asRead());
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
assert(isSubclass(slice->cls, int_cls));
int64_t n = slice->n;
_listSetitem(self, n, v); _listSetitem(self, n, v);
return None; 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 { extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept {
assert(isSubclass(op->cls, list_cls)); assert(isSubclass(op->cls, list_cls));
try { try {
_listSetitem(static_cast<BoxedList*>(op), i, newitem); listSetitemUnboxed(static_cast<BoxedList*>(op), i, newitem);
} catch (ExcInfo e) { } catch (ExcInfo e) {
abort(); abort();
} }
...@@ -460,8 +463,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { ...@@ -460,8 +463,12 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) { extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
return listSetitemInt(self, static_cast<BoxedInt*>(slice), v); 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) { } else if (slice->cls == slice_cls) {
return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v); return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v);
} else { } else {
...@@ -492,9 +499,11 @@ extern "C" Box* listDelitem(BoxedList* self, Box* slice) { ...@@ -492,9 +499,11 @@ extern "C" Box* listDelitem(BoxedList* self, Box* slice) {
LOCK_REGION(self->lock.asWrite()); LOCK_REGION(self->lock.asWrite());
Box* rtn; Box* rtn;
if (PyIndex_Check(slice)) {
if (isSubclass(slice->cls, int_cls)) { Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
rtn = listDelitemInt(self, static_cast<BoxedInt*>(slice)); if (i == -1 && PyErr_Occurred())
throwCAPIException();
rtn = listDelitemInt(self, (BoxedInt*)boxInt(i));
} else if (slice->cls == slice_cls) { } else if (slice->cls == slice_cls) {
rtn = listDelitemSlice(self, static_cast<BoxedSlice*>(slice)); rtn = listDelitemSlice(self, static_cast<BoxedSlice*>(slice));
} else { } else {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/inline/boxing.h" #include "runtime/inline/boxing.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
...@@ -104,12 +105,58 @@ extern "C" PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject* obj, int* overflo ...@@ -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 { extern "C" PyObject* PyLong_FromString(const char* str, char** pend, int base) noexcept {
RELEASE_ASSERT(pend == NULL, "unsupported"); RELEASE_ASSERT(pend == NULL, "unsupported");
// See comment in _longNew int sign = 1;
RELEASE_ASSERT(base >= 0, "unsupported"); 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(); 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); int r = mpz_init_set_str(rtn->n, str, base);
RELEASE_ASSERT(r == 0, ""); RELEASE_ASSERT(r == 0, "");
}
if (sign == -1)
mpz_neg(rtn->n, rtn->n);
return rtn; return rtn;
} }
...@@ -441,18 +488,8 @@ BoxedLong* _longNew(Box* val, Box* _base) { ...@@ -441,18 +488,8 @@ BoxedLong* _longNew(Box* val, Box* _base) {
raiseExcHelper(TypeError, "long() can't convert non-string with explicit base"); raiseExcHelper(TypeError, "long() can't convert non-string with explicit base");
BoxedString* s = static_cast<BoxedString*>(val); BoxedString* s = static_cast<BoxedString*>(val);
if (base == 0) { rtn = (BoxedLong*)PyLong_FromString(s->s.str().c_str(), NULL, base);
// mpz_init_set_str has the ability to auto-detect the base, but I doubt it's checkAndThrowCAPIException();
// 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, "");
} else { } else {
if (isSubclass(val->cls, long_cls)) { if (isSubclass(val->cls, long_cls)) {
BoxedLong* l = static_cast<BoxedLong*>(val); BoxedLong* l = static_cast<BoxedLong*>(val);
...@@ -920,6 +957,51 @@ Box* longDiv(BoxedLong* v1, Box* _v2) { ...@@ -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) { extern "C" Box* longDivmod(BoxedLong* lhs, Box* _rhs) {
if (!isSubclass(lhs->cls, long_cls)) if (!isSubclass(lhs->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'", raiseExcHelper(TypeError, "descriptor '__div__' requires a 'long' object but received a '%s'",
...@@ -1018,26 +1100,44 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) { ...@@ -1018,26 +1100,44 @@ Box* longRTrueDiv(BoxedLong* v1, Box* _v2) {
return boxFloat(lhs / (double)rhs); 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)) if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'", getTypeName(v1)); 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)) { if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2); BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
RELEASE_ASSERT(mpz_sgn(v2->n) >= 0, ""); 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), ""); RELEASE_ASSERT(mpz_fits_ulong_p(v2->n), "");
uint64_t n2 = mpz_get_ui(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); mpz_pow_ui(r->n, v1->n, n2);
}
return r; return r;
} else if (isSubclass(_v2->cls, int_cls)) { } else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2 = static_cast<BoxedInt*>(_v2); BoxedInt* v2 = static_cast<BoxedInt*>(_v2);
RELEASE_ASSERT(v2->n >= 0, ""); RELEASE_ASSERT(v2->n >= 0, "");
BoxedLong* r = new BoxedLong(); BoxedLong* r = new BoxedLong();
mpz_init(r->n); 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); mpz_pow_ui(r->n, v1->n, v2->n);
return r; return r;
} else { } else {
...@@ -1101,6 +1201,53 @@ void customised_free(void* ptr, size_t size) { ...@@ -1101,6 +1201,53 @@ void customised_free(void* ptr, size_t size) {
gc::gc_free(ptr); 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() { void setupLong() {
mp_set_memory_functions(customised_allocation, customised_realloc, customised_free); mp_set_memory_functions(customised_allocation, customised_realloc, customised_free);
...@@ -1114,6 +1261,8 @@ void setupLong() { ...@@ -1114,6 +1261,8 @@ void setupLong() {
long_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)longRdiv, UNKNOWN, 2))); 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("__truediv__", new BoxedFunction(boxRTFunction((void*)longTrueDiv, UNKNOWN, 2)));
long_cls->giveAttr("__rtruediv__", new BoxedFunction(boxRTFunction((void*)longRTrueDiv, 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))); long_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)longDivmod, UNKNOWN, 2)));
...@@ -1123,7 +1272,8 @@ void setupLong() { ...@@ -1123,7 +1272,8 @@ void setupLong() {
long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2))); long_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)longAdd, UNKNOWN, 2)));
long_cls->giveAttr("__radd__", long_cls->getattr("__add__")); 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("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2)));
long_cls->giveAttr("__rand__", long_cls->getattr("__and__")); long_cls->giveAttr("__rand__", long_cls->getattr("__and__"));
...@@ -1154,7 +1304,10 @@ void setupLong() { ...@@ -1154,7 +1304,10 @@ void setupLong() {
long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1))); 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("__trunc__", new BoxedFunction(boxRTFunction((void*)longTrunc, UNKNOWN, 1)));
long_cls->giveAttr("__index__", new BoxedFunction(boxRTFunction((void*)longIndex, LONG, 1)));
long_cls->freeze(); long_cls->freeze();
long_cls->tp_as_number->nb_power = long_pow;
} }
} }
...@@ -47,7 +47,7 @@ Box* longAdd(BoxedLong* lhs, Box* rhs); ...@@ -47,7 +47,7 @@ Box* longAdd(BoxedLong* lhs, Box* rhs);
Box* longSub(BoxedLong* lhs, Box* rhs); Box* longSub(BoxedLong* lhs, Box* rhs);
Box* longMul(BoxedLong* lhs, Box* rhs); Box* longMul(BoxedLong* lhs, Box* rhs);
Box* longDiv(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* longLshift(BoxedLong* lhs, Box* rhs);
Box* longRshift(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 ...@@ -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_GC;
tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS; tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE; tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE;
tp_flags |= Py_TPFLAGS_HAVE_INDEX;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)) if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
......
...@@ -2240,9 +2240,10 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) { ...@@ -2240,9 +2240,10 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
extern "C" Box* strGetitem(BoxedString* self, Box* slice) { extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
assert(isSubclass(self->cls, str_cls)); assert(isSubclass(self->cls, str_cls));
if (isSubclass(slice->cls, int_cls)) { if (PyIndex_Check(slice)) {
BoxedInt* islice = static_cast<BoxedInt*>(slice); Py_ssize_t n = PyNumber_AsSsize_t(slice, PyExc_IndexError);
int64_t n = islice->n; if (n == -1 && PyErr_Occurred())
throwCAPIException();
int size = self->size(); int size = self->size();
if (n < 0) if (n < 0)
n = size + n; n = size + n;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -146,9 +147,12 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept { ...@@ -146,9 +147,12 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept {
Box* tupleGetitem(BoxedTuple* self, Box* slice) { Box* tupleGetitem(BoxedTuple* self, Box* slice) {
assert(self->cls == tuple_cls); assert(self->cls == tuple_cls);
if (isSubclass(slice->cls, int_cls)) if (PyIndex_Check(slice)) {
return tupleGetitemInt(self, static_cast<BoxedInt*>(slice)); Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
else if (slice->cls == slice_cls) if (i == -1 && PyErr_Occurred())
throwCAPIException();
return tupleGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls)
return tupleGetitemSlice(self, static_cast<BoxedSlice*>(slice)); return tupleGetitemSlice(self, static_cast<BoxedSlice*>(slice));
else else
raiseExcHelper(TypeError, "tuple indices must be integers, not %s", getTypeName(slice)); raiseExcHelper(TypeError, "tuple indices must be integers, not %s", getTypeName(slice));
......
...@@ -40,6 +40,8 @@ print isinstance(1, int) ...@@ -40,6 +40,8 @@ print isinstance(1, int)
print isinstance(1, (float, int)) print isinstance(1, (float, int))
print isinstance(1, (float, (), (int, 3), 4)) print isinstance(1, (float, (), (int, 3), 4))
print pow(11, 42)
print pow(11, 42, 75)
print divmod(5, 2) print divmod(5, 2)
print divmod(5L, -2) print divmod(5L, -2)
try: try:
......
# expected: fail
# - long % int
import sys import sys
P = 1000000007 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): ...@@ -13,6 +13,9 @@ for i in xrange(1, 12):
print 1 ** 0 print 1 ** 0
print 0 ** 0 print 0 ** 0
print -1 ** 0 print -1 ** 0
print (11).__pow__(5, 50)
print (11).__pow__(32, 50)
print (11).__index__()
for i in (-10, 10, 0, -15): for i in (-10, 10, 0, -15):
print i, i.__hex__(), i.__oct__() print i, i.__hex__(), i.__oct__()
......
...@@ -4,6 +4,7 @@ print l * 5 ...@@ -4,6 +4,7 @@ print l * 5
l[0] = 1 l[0] = 1
print l print l
print l[2] print l[2]
print l[2L]
l = range(5) l = range(5)
while l: while l:
......
...@@ -13,6 +13,7 @@ def test(a, b): ...@@ -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.__sub__(b), b.__sub__(a)
print a * b, b * a, a.__mul__(b), b.__mul__(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.__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 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): if not isinstance(a, float) and not isinstance(b, float):
print a ^ b, a | b, a & b print a ^ b, a | b, a & b
...@@ -55,10 +56,15 @@ print ~(-10L) ...@@ -55,10 +56,15 @@ print ~(-10L)
print -(1L) print -(1L)
print 1L**2L print 1L**2L
print 1L**2 print 1L**2
print (11L).__pow__(32, 50L)
print (11L).__index__()
print long("100", 16) print long("100", 16)
print long("100", 10) print long("100", 10)
print long("100", 26) 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.1)
print long(1.9) print long(1.9)
print long(-1.9) print long(-1.9)
......
...@@ -133,6 +133,7 @@ except TypeError, e: ...@@ -133,6 +133,7 @@ except TypeError, e:
t = (1, "2") t = (1, "2")
print t[0] print t[0]
print t[1] print t[1]
print t[1L]
t = (1, 2, 'a', 'b', 'c') t = (1, 2, 'a', 'b', 'c')
print t[::-1] print t[::-1]
......
...@@ -15,3 +15,6 @@ for i in xrange(10, -10, -3): ...@@ -15,3 +15,6 @@ for i in xrange(10, -10, -3):
for i in xrange(0): for i in xrange(0):
print i 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