Commit d5356e46 authored by Marius Wachtler's avatar Marius Wachtler

Add 'int << long', 'int >> long', '~long', 'long | long', long.__hex__(), long.__oct__()

parent 020ce1ba
......@@ -665,6 +665,9 @@ extern "C" Box* intLShift(BoxedInt* lhs, Box* rhs) {
raiseExcHelper(TypeError, "descriptor '__lshift__' requires a 'int' object but received a '%s'",
getTypeName(lhs));
if (rhs->cls == long_cls)
return longLshift(boxLong(lhs->n), rhs);
if (rhs->cls != int_cls) {
return NotImplemented;
}
......@@ -781,6 +784,9 @@ extern "C" Box* intRShift(BoxedInt* lhs, Box* rhs) {
raiseExcHelper(TypeError, "descriptor '__rshift__' requires a 'int' object but received a '%s'",
getTypeName(lhs));
if (rhs->cls == long_cls)
return longRshift(boxLong(lhs->n), rhs);
if (rhs->cls != int_cls) {
return NotImplemented;
}
......@@ -1049,7 +1055,7 @@ void setupInt() {
_addFuncIntUnknown("__ge__", BOXED_BOOL, (void*)intGeInt, (void*)intGe);
_addFuncIntUnknown("__lshift__", UNKNOWN, (void*)intLShiftInt, (void*)intLShift);
_addFuncIntUnknown("__rshift__", BOXED_INT, (void*)intRShiftInt, (void*)intRShift);
_addFuncIntUnknown("__rshift__", UNKNOWN, (void*)intRShiftInt, (void*)intRShift);
int_cls->giveAttr("__invert__", new BoxedFunction(boxRTFunction((void*)intInvert, BOXED_INT, 1)));
int_cls->giveAttr("__pos__", new BoxedFunction(boxRTFunction((void*)intPos, BOXED_INT, 1)));
......
......@@ -18,6 +18,8 @@
#include <gmp.h>
#include <sstream>
#include "llvm/Support/raw_ostream.h"
#include "core/common.h"
#include "core/options.h"
#include "core/stats.h"
......@@ -216,8 +218,47 @@ extern "C" double PyLong_AsDouble(PyObject* vv) noexcept {
return mpz_get_d(l->n);
}
/* Convert the long to a string object with given base,
appending a base prefix of 0[box] if base is 2, 8 or 16.
Add a trailing "L" if addL is non-zero.
If newstyle is zero, then use the pre-2.6 behavior of octal having
a leading "0", instead of the prefix "0o" */
extern "C" PyAPI_FUNC(PyObject*) _PyLong_Format(PyObject* aa, int base, int addL, int newstyle) noexcept {
Py_FatalError("unimplemented");
BoxedLong* v = (BoxedLong*)aa;
RELEASE_ASSERT(isSubclass(v->cls, long_cls), "");
RELEASE_ASSERT(base >= 2 && base <= 62, "");
bool is_negative = mpz_sgn(v->n) == -1;
int space_required = mpz_sizeinbase(v->n, base) + 2;
char* buf = (char*)malloc(space_required);
mpz_get_str(buf, base, v->n);
std::string str;
llvm::raw_string_ostream os(str);
if (is_negative)
os << '-';
if (base == 2)
os << "0b";
else if (base == 8)
os << (newstyle ? "0o" : "0");
else if (base == 16)
os << "0x";
if (is_negative)
os << buf + 1; // +1 to remove sign
else
os << buf;
if (addL)
os << "L";
os.flush();
auto rtn = new BoxedString(std::move(str));
free(buf);
return rtn;
}
extern "C" PyObject* PyLong_FromDouble(double v) noexcept {
......@@ -474,30 +515,25 @@ Box* longInt(Box* v) {
Box* longRepr(BoxedLong* v) {
if (!isSubclass(v->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__repr__' requires a 'long' object but received a '%s'", getTypeName(v));
int space_required = mpz_sizeinbase(v->n, 10) + 2; // basic size
space_required += 1; // 'L' suffix
char* buf = (char*)malloc(space_required);
mpz_get_str(buf, 10, v->n);
strcat(buf, "L");
auto rtn = new BoxedString(buf);
free(buf);
return rtn;
return _PyLong_Format(v, 10, 1 /* add L */, 0);
}
Box* longStr(BoxedLong* v) {
if (!isSubclass(v->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__str__' requires a 'long' object but received a '%s'", getTypeName(v));
int space_required = mpz_sizeinbase(v->n, 10) + 2;
char* buf = (char*)malloc(space_required);
mpz_get_str(buf, 10, v->n);
return _PyLong_Format(v, 10, 0 /* no L */, 0);
}
auto rtn = new BoxedString(buf);
free(buf);
Box* longHex(BoxedLong* v) {
if (!isSubclass(v->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__hex__' requires a 'long' object but received a '%s'", getTypeName(v));
return _PyLong_Format(v, 16, 1 /* add L */, 0);
}
return rtn;
Box* longOct(BoxedLong* v) {
if (!isSubclass(v->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__oct__' requires a 'long' object but received a '%s'", getTypeName(v));
return _PyLong_Format(v, 8, 1 /* add L */, 0);
}
Box* longNeg(BoxedLong* v1) {
......@@ -544,6 +580,7 @@ Box* longAdd(BoxedLong* v1, Box* _v2) {
}
}
// TODO: split common code out into a helper function
extern "C" Box* longAnd(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__and__' requires a 'long' object but received a '%s'", getTypeName(v1));
......@@ -570,6 +607,32 @@ extern "C" Box* longAnd(BoxedLong* v1, Box* _v2) {
return NotImplemented;
}
extern "C" Box* longOr(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__or__' requires a 'long' object but received a '%s'", getTypeName(v1));
if (isSubclass(_v2->cls, long_cls)) {
BoxedLong* v2 = static_cast<BoxedLong*>(_v2);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_ior(r->n, v1->n, v2->n);
return r;
} else if (isSubclass(_v2->cls, int_cls)) {
BoxedInt* v2_int = static_cast<BoxedInt*>(_v2);
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_t v2_long;
mpz_init(v2_long);
if (v2_int->n >= 0)
mpz_init_set_ui(v2_long, v2_int->n);
else
mpz_init_set_si(v2_long, v2_int->n);
mpz_ior(r->n, v1->n, v2_long);
return r;
}
return NotImplemented;
}
extern "C" Box* longXor(BoxedLong* v1, Box* _v2) {
if (!isSubclass(v1->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__xor__' requires a 'long' object but received a '%s'", getTypeName(v1));
......@@ -924,6 +987,17 @@ Box* longPow(BoxedLong* v1, Box* _v2) {
return r;
}
extern "C" Box* longInvert(BoxedLong* v) {
if (!isSubclass(v->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__invert__' requires a 'long' object but received a '%s'",
getTypeName(v));
BoxedLong* r = new BoxedLong();
mpz_init(r->n);
mpz_com(r->n, v->n);
return r;
}
Box* longNonzero(BoxedLong* self) {
if (!isSubclass(self->cls, long_cls))
raiseExcHelper(TypeError, "descriptor '__pow__' requires a 'long' object but received a '%s'",
......@@ -983,6 +1057,8 @@ void setupLong() {
long_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)longAnd, UNKNOWN, 2)));
long_cls->giveAttr("__rand__", long_cls->getattr("__and__"));
long_cls->giveAttr("__or__", new BoxedFunction(boxRTFunction((void*)longOr, UNKNOWN, 2)));
long_cls->giveAttr("__ror__", long_cls->getattr("__or__"));
long_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)longXor, UNKNOWN, 2)));
long_cls->giveAttr("__rxor__", long_cls->getattr("__xor__"));
......@@ -999,7 +1075,10 @@ void setupLong() {
long_cls->giveAttr("__int__", new BoxedFunction(boxRTFunction((void*)longInt, UNKNOWN, 1)));
long_cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)longRepr, STR, 1)));
long_cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)longStr, STR, 1)));
long_cls->giveAttr("__hex__", new BoxedFunction(boxRTFunction((void*)longHex, STR, 1)));
long_cls->giveAttr("__oct__", new BoxedFunction(boxRTFunction((void*)longOct, STR, 1)));
long_cls->giveAttr("__invert__", new BoxedFunction(boxRTFunction((void*)longInvert, UNKNOWN, 1)));
long_cls->giveAttr("__nonzero__", new BoxedFunction(boxRTFunction((void*)longNonzero, BOXED_BOOL, 1)));
long_cls->giveAttr("__hash__", new BoxedFunction(boxRTFunction((void*)longHash, BOXED_INT, 1)));
......
......@@ -48,6 +48,12 @@ 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* longLshift(BoxedLong* lhs, Box* rhs);
Box* longRshift(BoxedLong* lhs, Box* rhs);
Box* longHex(BoxedLong* v);
Box* longOct(BoxedLong* v);
Box* longStr(BoxedLong* v);
}
#endif
......@@ -30,6 +30,7 @@
#include "gc/collector.h"
#include "runtime/capi.h"
#include "runtime/dict.h"
#include "runtime/long.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -342,8 +343,138 @@ Py_LOCAL_INLINE(PyObject*) getnextarg(PyObject* args, Py_ssize_t arglen, Py_ssiz
return NULL;
}
extern "C" PyObject* _PyString_FormatLong(PyObject*, int, int, int, const char**, int*) noexcept {
Py_FatalError("unimplemented");
extern "C" PyObject* _PyString_FormatLong(PyObject* val, int flags, int prec, int type, const char** pbuf,
int* plen) noexcept {
// Pyston change:
RELEASE_ASSERT(val->cls == long_cls, "");
PyObject* result = NULL;
char* buf;
Py_ssize_t i;
int sign; /* 1 if '-', else 0 */
int len; /* number of characters */
Py_ssize_t llen;
int numdigits; /* len == numnondigits + numdigits */
int numnondigits = 0;
switch (type) {
case 'd':
case 'u':
// Pyston change:
// result = Py_TYPE(val)->tp_str(val);
result = longStr((BoxedLong*)val);
break;
case 'o':
// Pyston change:
// result = Py_TYPE(val)->tp_as_number->nb_oct(val);
result = longOct((BoxedLong*)val);
break;
case 'x':
case 'X':
numnondigits = 2;
// Pyston change:
// result = Py_TYPE(val)->tp_as_number->nb_hex(val);
result = longHex((BoxedLong*)val);
break;
default:
assert(!"'type' not in [duoxX]");
}
if (!result)
return NULL;
buf = PyString_AsString(result);
if (!buf) {
Py_DECREF(result);
return NULL;
}
/* To modify the string in-place, there can only be one reference. */
// Pyston change:
// if (Py_REFCNT(result) != 1) {
if (0) {
PyErr_BadInternalCall();
return NULL;
}
llen = PyString_Size(result);
if (llen > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "string too large in _PyString_FormatLong");
return NULL;
}
len = (int)llen;
if (buf[len - 1] == 'L') {
--len;
buf[len] = '\0';
}
sign = buf[0] == '-';
numnondigits += sign;
numdigits = len - numnondigits;
assert(numdigits > 0);
/* Get rid of base marker unless F_ALT */
if ((flags & F_ALT) == 0) {
/* Need to skip 0x, 0X or 0. */
int skipped = 0;
switch (type) {
case 'o':
assert(buf[sign] == '0');
/* If 0 is only digit, leave it alone. */
if (numdigits > 1) {
skipped = 1;
--numdigits;
}
break;
case 'x':
case 'X':
assert(buf[sign] == '0');
assert(buf[sign + 1] == 'x');
skipped = 2;
numnondigits -= 2;
break;
}
if (skipped) {
buf += skipped;
len -= skipped;
if (sign)
buf[0] = '-';
}
assert(len == numnondigits + numdigits);
assert(numdigits > 0);
}
/* Fill with leading zeroes to meet minimum width. */
if (prec > numdigits) {
PyObject* r1 = PyString_FromStringAndSize(NULL, numnondigits + prec);
char* b1;
if (!r1) {
Py_DECREF(result);
return NULL;
}
b1 = PyString_AS_STRING(r1);
for (i = 0; i < numnondigits; ++i)
*b1++ = *buf++;
for (i = 0; i < prec - numdigits; i++)
*b1++ = '0';
for (i = 0; i < numdigits; i++)
*b1++ = *buf++;
*b1 = '\0';
Py_DECREF(result);
result = r1;
buf = PyString_AS_STRING(result);
len = numnondigits + prec;
}
/* Fix up case for hex conversions. */
if (type == 'X') {
/* Need to convert all lower case letters to upper case.
and need to convert 0x to 0X (and -0x to -0X). */
for (i = 0; i < len; i++)
if (buf[i] >= 'a' && buf[i] <= 'x')
buf[i] -= 'a' - 'A';
}
*pbuf = buf;
*plen = len;
return result;
}
static PyObject* formatfloat(PyObject* v, int flags, int prec, int type) {
......
......@@ -14,7 +14,9 @@ def test(a, b):
print a * b, b * a, a.__mul__(b), b.__mul__(a)
print a / b, b / a, a.__div__(b), b.__div__(a)
print repr(a), repr(b), a < b, a > b, a <= b, a >= b, a == b, a != b
# print a ^ b, a | b, a & b
if not isinstance(a, float) and not isinstance(b, float):
print a ^ b, a | b, a & b
print a.__hex__(), b.__hex__(), a.__oct__(), b.__oct__()
print 1L / 5L
......@@ -22,7 +24,7 @@ print -1L / 5L
print 1L / -5L
print -1L / -5L
for a in [-5, -1, 1, 5, -2L, -1L, 1L, 2L]:
for a in [-5, -1, 1, 5, -2L, -1L, 1L, 2L, 15L]:
for b in [-5, -1, 1, 5, -2L, -1L, 1L, 2L]:
test(a, b)
......@@ -36,6 +38,8 @@ print (-2L).__rdiv__(1)
print (1L) << (2L)
print (1L) << (2)
print (1) << (1L)
print (1) << (128L)
try:
print (1L) << (-1L)
except ValueError, e:
......@@ -45,6 +49,10 @@ try:
except ValueError, e:
print e
print ~(1L)
print ~(10L)
print ~(-10L)
print long("100", 16)
print long("100", 10)
print long("100", 26)
......
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