Commit 48ec63a6 authored by Marius Wachtler's avatar Marius Wachtler Committed by GitHub

Merge pull request #1243 from undingen/tp_str

implement tp_str and tp_repr for more of our builtin types
parents d150b6e3 5e33fe60
......@@ -457,7 +457,7 @@ struct _typeobject {
void* _hcls;
void* _hcattrs;
char _ics[40];
char _ics[48];
int _attrs_offset;
char _flags[7]; // These are bools in C++
void* _tpp_descr_get;
......
......@@ -630,33 +630,28 @@ extern "C" int _PyObject_SlotCompare(PyObject* self, PyObject* other) noexcept {
static PyObject* slot_tp_repr(PyObject* self) noexcept {
STAT_TIMER(t0, "us_timer_slot_tprepr", SLOT_AVOIDABILITY(self));
PyObject* func, *res;
static PyObject* repr_str;
func = lookup_method(self, "__repr__", &repr_str);
if (func != NULL) {
res = PyEval_CallObject(func, NULL);
Py_DECREF(func);
return res;
try {
PyObject* res = self->reprIC();
if (res != NULL)
return res;
return PyString_FromFormat("<%s object at %p>", Py_TYPE(self)->tp_name, self);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
PyErr_Clear();
return PyString_FromFormat("<%s object at %p>", Py_TYPE(self)->tp_name, self);
}
static PyObject* slot_tp_str(PyObject* self) noexcept {
STAT_TIMER(t0, "us_timer_slot_tpstr", SLOT_AVOIDABILITY(self));
PyObject* func, *res;
static PyObject* str_str;
func = lookup_method(self, "__str__", &str_str);
if (func != NULL) {
res = PyEval_CallObject(func, NULL);
Py_DECREF(func);
return res;
} else {
PyErr_Clear();
try {
PyObject* res = self->strIC();
if (res != NULL)
return res;
return slot_tp_repr(self);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
......
......@@ -41,12 +41,14 @@ public:
PyCFunction getFunction() { return method_def->ml_meth; }
static BoxedString* __repr__(BoxedCApiFunction* self) {
assert(self->cls == capifunc_cls);
template <ExceptionStyle S> static Box* __repr__(Box* _self) noexcept(S == CAPI) {
if (!isSubclass(_self->cls, capifunc_cls))
return setDescrTypeError<S>(_self, "capifunc", "__repr__");
BoxedCApiFunction* self = (BoxedCApiFunction*)_self;
if (self->passthrough == NULL)
return (BoxedString*)PyString_FromFormat("<built-in function %s>", self->method_def->ml_name);
return (BoxedString*)PyString_FromFormat("<built-in method %s of %s object at %p>", self->method_def->ml_name,
self->passthrough->cls->tp_name, self->passthrough);
return callCAPIFromStyle<S>(PyString_FromFormat, "<built-in function %s>", self->method_def->ml_name);
return callCAPIFromStyle<S>(PyString_FromFormat, "<built-in method %s of %s object at %p>",
self->method_def->ml_name, self->passthrough->cls->tp_name, self->passthrough);
}
static Box* __call__(BoxedCApiFunction* self, BoxedTuple* varargs, BoxedDict* kwargs);
......
......@@ -890,7 +890,8 @@ public:
// Only valid for hc-backed instances:
BORROWED(Box*) getAttrWrapper();
Box* reprIC();
Box* reprIC(); // returns null on nonexistent!
Box* strIC(); // returns null on nonexistent!
BoxedString* reprICAsString();
bool nonzeroIC();
Box* hasnextOrNullIC();
......
......@@ -30,9 +30,11 @@ extern "C" Box* boolNonzero(BoxedBool* v) {
return incref(v);
}
extern "C" Box* boolRepr(BoxedBool* v) {
template <ExceptionStyle S> Box* boolRepr(Box* v) noexcept(S == CAPI) {
static BoxedString* true_str = getStaticString("True");
static BoxedString* false_str = getStaticString("False");
if (!PyBool_Check(v))
return setDescrTypeError<S>(v, "bool", "__repr__");
if (v == Py_True)
return incref(true_str);
......@@ -92,7 +94,7 @@ void setupBool() {
bool_cls->tp_as_number = &bool_as_number;
bool_cls->giveAttr("__nonzero__", new BoxedFunction(FunctionMetadata::create((void*)boolNonzero, BOXED_BOOL, 1)));
bool_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)boolRepr, STR, 1)));
bool_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)boolRepr<CXX>, STR, 1)));
bool_cls->giveAttr("__hash__", new BoxedFunction(FunctionMetadata::create((void*)boolHash, BOXED_INT, 1)));
bool_cls->giveAttr("__new__",
......@@ -105,5 +107,6 @@ void setupBool() {
bool_cls->freeze();
bool_cls->tp_hash = (hashfunc)bool_hash;
bool_cls->tp_repr = boolRepr<CAPI>;
}
}
......@@ -1907,8 +1907,8 @@ extern "C" int PyCFunction_ClearFreeList() noexcept {
}
void setupCAPI() {
capifunc_cls->giveAttr("__repr__",
new BoxedFunction(FunctionMetadata::create((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
capifunc_cls->giveAttr(
"__repr__", new BoxedFunction(FunctionMetadata::create((void*)BoxedCApiFunction::__repr__<CXX>, UNKNOWN, 1)));
auto capi_call
= new BoxedFunction(FunctionMetadata::create((void*)BoxedCApiFunction::__call__, UNKNOWN, 1, true, true));
......@@ -1920,5 +1920,6 @@ void setupCAPI() {
capifunc_cls->giveAttrMember("__module__", T_OBJECT, offsetof(BoxedCApiFunction, module));
capifunc_cls->freeze();
capifunc_cls->tp_repr = BoxedCApiFunction::__repr__<CAPI>;
}
}
......@@ -438,16 +438,12 @@ Box* complexNonzero(BoxedComplex* self) {
return boxBool(res);
}
Box* complexStr(BoxedComplex* self) {
template <ExceptionStyle S> Box* complexStr(Box* self) noexcept(S == CAPI) {
if (!PyComplex_Check(self))
raiseExcHelper(TypeError, "descriptor '__str__' requires a 'complex' object but received a '%s'",
getTypeName(self));
return setDescrTypeError<S>(self, "complex", "__str__");
Box* r = complex_format((PyComplexObject*)self, 12, 'g');
if (!r) {
throwCAPIException();
}
return r;
return callCAPIFromStyle<S>(complex_format, (PyComplexObject*)self, 12, 'g');
}
Box* complexInt(BoxedComplex* self) {
......@@ -474,16 +470,11 @@ Box* complexLong(BoxedComplex* self) {
raiseExcHelper(TypeError, "can't convert complex to long");
}
Box* complexRepr(BoxedComplex* self) {
template <ExceptionStyle S> Box* complexRepr(Box* self) noexcept(S == CAPI) {
if (!PyComplex_Check(self))
raiseExcHelper(TypeError, "descriptor '__repr__' requires a 'complex' object but received a '%s'",
getTypeName(self));
return setDescrTypeError<S>(self, "complex", "__repr__");
Box* r = complex_format((PyComplexObject*)self, 16, 'g');
if (!r) {
throwCAPIException();
}
return r;
return callCAPIFromStyle<S>(complex_format, (PyComplexObject*)self, 16, 'g');
}
template <ExceptionStyle S> Box* complexNew(BoxedClass* cls, Box* real, Box* imag) noexcept(S == CAPI) {
......@@ -806,11 +797,11 @@ void setupComplex() {
complex_cls->giveAttr("__neg__", new BoxedFunction(FunctionMetadata::create((void*)complexNeg, BOXED_COMPLEX, 1)));
complex_cls->giveAttr("__pos__", new BoxedFunction(FunctionMetadata::create((void*)complexPos, BOXED_COMPLEX, 1)));
complex_cls->giveAttr("__hash__", new BoxedFunction(FunctionMetadata::create((void*)complexHash, BOXED_INT, 1)));
complex_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)complexStr, STR, 1)));
complex_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)complexStr<CXX>, STR, 1)));
complex_cls->giveAttr("__int__", new BoxedFunction(FunctionMetadata::create((void*)complexInt, UNKNOWN, 1)));
complex_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)complexFloat, UNKNOWN, 1)));
complex_cls->giveAttr("__long__", new BoxedFunction(FunctionMetadata::create((void*)complexLong, UNKNOWN, 1)));
complex_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)complexRepr, STR, 1)));
complex_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)complexRepr<CXX>, STR, 1)));
complex_cls->giveAttrMember("real", T_DOUBLE, offsetof(BoxedComplex, real), true);
complex_cls->giveAttrMember("imag", T_DOUBLE, offsetof(BoxedComplex, imag), true);
......@@ -824,6 +815,8 @@ void setupComplex() {
add_operators(complex_cls);
complex_cls->freeze();
complex_cls->tp_str = complexStr<CAPI>;
complex_cls->tp_repr = complexRepr<CAPI>;
complex_cls->tp_as_number->nb_negative = (unaryfunc)complex_neg;
complex_cls->tp_richcompare = complex_richcompare;
}
......
......@@ -780,16 +780,16 @@ extern "C" Box* floatFloat(BoxedFloat* self) {
return boxFloat(self->d);
}
Box* floatStr(BoxedFloat* self) {
template <ExceptionStyle S> Box* floatStr(BoxedFloat* self) noexcept(S == CAPI) {
if (!PyFloat_Check(self))
raiseExcHelper(TypeError, "descriptor '__str__' requires a 'float' object but received a '%s'",
getTypeName(self));
return float_str_or_repr(self->d, PyFloat_STR_PRECISION, 'g');
return setDescrTypeError<S>(self, "float", "__str__");
return callCAPIFromStyle<S>(float_str_or_repr, self->d, PyFloat_STR_PRECISION, 'g');
}
Box* floatRepr(BoxedFloat* self) {
return float_str_or_repr(self->d, 0, 'r');
template <ExceptionStyle S> Box* floatRepr(BoxedFloat* self) noexcept(S == CAPI) {
if (!PyFloat_Check(self))
return setDescrTypeError<S>(self, "float", "__repr__");
return callCAPIFromStyle<S>(float_str_or_repr, self->d, 0, 'r');
}
Box* floatToInt(BoxedFloat* self) {
......@@ -996,8 +996,8 @@ void setupFloat() {
// float_cls->giveAttr("__nonzero__", new BoxedFunction(FunctionMetadata::create((void*)floatNonzero, NULL, 1)));
float_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)floatFloat, BOXED_FLOAT, 1)));
float_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)floatStr, STR, 1)));
float_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)floatRepr, STR, 1)));
float_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)floatStr<CXX>, STR, 1)));
float_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)floatRepr<CXX>, STR, 1)));
float_cls->giveAttr("__coerce__", new BoxedFunction(FunctionMetadata::create((void*)floatCoerce, UNKNOWN, 2)));
float_cls->giveAttr("__trunc__", new BoxedFunction(FunctionMetadata::create((void*)floatTrunc, UNKNOWN, 1)));
......@@ -1021,8 +1021,9 @@ void setupFloat() {
_PyFloat_Init();
float_cls->tp_str = float_str;
float_cls->tp_as_number->nb_power = float_pow;
float_cls->tp_new = (newfunc)floatNewPacked;
float_cls->tp_repr = (reprfunc)floatRepr<CAPI>;
float_cls->tp_str = (reprfunc)floatStr<CAPI>;
}
}
......@@ -60,7 +60,11 @@ extern "C" PyObject* PyList_AsTuple(PyObject* v) noexcept {
return BoxedTuple::create(l->size, &l->elts->elts[0]);
}
extern "C" Box* listRepr(BoxedList* self) {
extern "C" Box* listRepr(Box* _self) {
if (!PyList_Check(_self))
return setDescrTypeError<CXX>(_self, "list", "__repr__");
BoxedList* self = (BoxedList*)_self;
std::vector<char> chars;
int status = Py_ReprEnter((PyObject*)self);
......@@ -98,6 +102,10 @@ extern "C" Box* listRepr(BoxedList* self) {
return boxString(llvm::StringRef(&chars[0], chars.size()));
}
Box* list_repr(Box* self) noexcept {
return callCXXFromStyle<CAPI>(listRepr, self);
}
extern "C" Box* listNonzero(BoxedList* self) {
return boxBool(self->size != 0);
}
......@@ -1527,6 +1535,7 @@ void setupList() {
list_cls->giveAttrBorrowed("__hash__", None);
list_cls->freeze();
list_cls->tp_iter = listIter;
list_cls->tp_repr = list_repr;
list_cls->tp_as_sequence->sq_length = list_length;
list_cls->tp_as_sequence->sq_concat = (binaryfunc)list_concat;
......
......@@ -823,16 +823,16 @@ Box* longFloat(BoxedLong* v) {
return longToFloat(v);
}
Box* longRepr(BoxedLong* v) {
template <ExceptionStyle S> Box* longRepr(Box* v) noexcept(S == CAPI) {
if (!PyLong_Check(v))
raiseExcHelper(TypeError, "descriptor '__repr__' requires a 'long' object but received a '%s'", getTypeName(v));
return _PyLong_Format(v, 10, 1 /* add L */, 0);
return setDescrTypeError<S>(v, "long", "__repr__");
return callCAPIFromStyle<S>(_PyLong_Format, v, 10, 1 /* add L */, 0);
}
Box* longStr(BoxedLong* v) {
template <ExceptionStyle S> Box* longStr(Box* v) noexcept(S == CAPI) {
if (!PyLong_Check(v))
raiseExcHelper(TypeError, "descriptor '__str__' requires a 'long' object but received a '%s'", getTypeName(v));
return _PyLong_Format(v, 10, 0 /* no L */, 0);
return setDescrTypeError<S>(v, "long", "__str__");
return callCAPIFromStyle<S>(_PyLong_Format, v, 10, 0 /* no L */, 0);
}
Box* long__format__(BoxedLong* self, Box* format_spec) noexcept {
......@@ -1744,8 +1744,8 @@ void setupLong() {
long_cls->giveAttr("__int__", new BoxedFunction(FunctionMetadata::create((void*)longInt, UNKNOWN, 1)));
long_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)longFloat, UNKNOWN, 1)));
long_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)longRepr, STR, 1)));
long_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)longStr, STR, 1)));
long_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)longRepr<CXX>, STR, 1)));
long_cls->giveAttr("__str__", new BoxedFunction(FunctionMetadata::create((void*)longStr<CXX>, STR, 1)));
long_cls->giveAttr("__format__", new BoxedFunction(FunctionMetadata::create((void*)longFormat, STR, 2)));
long_cls->giveAttr("__bin__", new BoxedFunction(FunctionMetadata::create((void*)longBin, STR, 1)));
long_cls->giveAttr("__hex__", new BoxedFunction(FunctionMetadata::create((void*)longHex, STR, 1)));
......@@ -1786,5 +1786,7 @@ void setupLong() {
long_cls->tp_as_number->nb_power = long_pow;
long_cls->tp_hash = long_hash;
long_cls->tp_repr = longRepr<CAPI>;
long_cls->tp_str = longStr<CAPI>;
}
}
......@@ -39,8 +39,6 @@ public:
extern "C" Box* createLong(llvm::StringRef s);
extern "C" BoxedLong* boxLong(int64_t n);
Box* longRepr(BoxedLong* v);
Box* longNeg(BoxedLong* lhs);
Box* longAbs(BoxedLong* v1);
......
......@@ -213,6 +213,21 @@ static const char* objectNewParameterTypeErrorMsg() {
}
}
// use this like:
// if (!PyBool_Check(v))
// return setDescrTypeError<S>(v, "bool", "__repr__");
// ...
template <ExceptionStyle S>
Box* __attribute__((warn_unused_result))
setDescrTypeError(Box* got, const char* expected_cls_name, const char* descr_name) {
if (S == CXX)
raiseExcHelper((PyTypeObject*)PyExc_TypeError, "descriptor '%s' requires a '%s' object but received a '%s'",
descr_name, expected_cls_name, getTypeName(got));
PyErr_Format(PyExc_TypeError, "descriptor '%s' requires a '%s' object but received a '%s'", descr_name,
expected_cls_name, getTypeName(got));
return NULL;
}
inline std::tuple<Box*, Box*, Box*, Box**> getTupleFromArgsArray(Box** args, int num_args) {
Box* arg1 = num_args >= 1 ? args[0] : nullptr;
Box* arg2 = num_args >= 2 ? args[1] : nullptr;
......
......@@ -248,9 +248,11 @@ Box* setInit(Box* _self, Box* container, BoxedDict* kwargs) {
return incref(None);
}
static Box* setRepr(BoxedSet* self) {
RELEASE_ASSERT(PyAnySet_Check(self), "");
static Box* setRepr(Box* _self) {
if (!PyAnySet_Check(_self))
return setDescrTypeError<CXX>(_self, "set", "__repr__");
BoxedSet* self = (BoxedSet*)_self;
std::vector<char> chars;
int status = Py_ReprEnter((PyObject*)self);
......@@ -298,6 +300,9 @@ static Box* setRepr(BoxedSet* self) {
Py_ReprLeave((PyObject*)self);
return boxString(llvm::StringRef(&chars[0], chars.size()));
}
static Box* set_repr(Box* self) noexcept {
return callCXXFromStyle<CAPI>(setRepr, self);
}
static void _setSymmetricDifferenceUpdate(BoxedSet* self, Box* other) {
if (!PyAnySet_Check(other)) {
......@@ -966,11 +971,9 @@ void setupSet() {
frozenset_cls->giveAttr(
"__new__", new BoxedFunction(FunctionMetadata::create((void*)frozensetNew, UNKNOWN, 2, false, true), { NULL }));
Box* set_repr = new BoxedFunction(FunctionMetadata::create((void*)setRepr, STR, 1));
set_cls->giveAttrBorrowed("__repr__", set_repr);
set_cls->giveAttrBorrowed("__str__", set_repr);
frozenset_cls->giveAttrBorrowed("__repr__", set_repr);
frozenset_cls->giveAttr("__str__", set_repr);
Box* set_repr_func = new BoxedFunction(FunctionMetadata::create((void*)setRepr, STR, 1));
set_cls->giveAttrBorrowed("__repr__", set_repr_func);
frozenset_cls->giveAttr("__repr__", set_repr_func);
std::vector<ConcreteCompilerType*> v_ss, v_sf, v_su, v_ff, v_fs, v_fu;
v_ss.push_back(SET);
......@@ -1083,7 +1086,7 @@ void setupSet() {
set_cls->freeze();
frozenset_cls->freeze();
set_cls->tp_iter = (decltype(set_cls->tp_iter))setIter;
frozenset_cls->tp_iter = (decltype(frozenset_cls->tp_iter))setIter;
frozenset_cls->tp_repr = set_cls->tp_repr = set_repr;
frozenset_cls->tp_iter = set_cls->tp_iter = (decltype(set_cls->tp_iter))setIter;
}
}
......@@ -259,9 +259,11 @@ extern "C" Py_ssize_t PyTuple_Size(PyObject* op) noexcept {
return static_cast<BoxedTuple*>(op)->size();
}
Box* tupleRepr(BoxedTuple* t) {
Box* tupleRepr(Box* _t) {
if (!PyTuple_Check(_t))
return setDescrTypeError<CXX>(_t, "tuple", "__repr__");
assert(PyTuple_Check(t));
BoxedTuple* t = (BoxedTuple*)_t;
int n;
std::vector<char> chars;
int status = Py_ReprEnter((PyObject*)t);
......@@ -308,6 +310,9 @@ Box* tupleRepr(BoxedTuple* t) {
return boxString(llvm::StringRef(&chars[0], chars.size()));
}
static Box* tuple_repr(Box* v) noexcept {
return callCXXFromStyle<CAPI>(tupleRepr, v);
}
Box* tupleNonzero(BoxedTuple* self) {
RELEASE_ASSERT(PyTuple_Check(self), "");
......@@ -810,6 +815,7 @@ void setupTuple() {
tuple_cls->tp_as_sequence->sq_repeat = (ssizeargfunc)tuplerepeat;
tuple_cls->tp_as_sequence->sq_contains = (objobjproc)tuplecontains;
tuple_cls->tp_iter = tupleIter;
tuple_cls->tp_repr = tuple_repr;
tuple_cls->tp_as_mapping->mp_length = (lenfunc)tuplelength;
tuple_cls->tp_as_mapping->mp_subscript = (binaryfunc)tupleGetitem<CAPI>;
......
......@@ -229,16 +229,31 @@ Box* BoxedClass::callReprIC(Box* obj) {
assert(obj->cls == this);
auto ic = repr_ic.get();
if (!ic) {
if (unlikely(!ic)) {
ic = new CallattrIC();
repr_ic.reset(ic);
}
static BoxedString* repr_str = getStaticString("__repr__");
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = false, .argspec = ArgPassSpec(0) };
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(0) };
return ic->call(obj, repr_str, callattr_flags, nullptr, nullptr, nullptr, nullptr, nullptr);
}
Box* BoxedClass::callStrIC(Box* obj) {
assert(obj->cls == this);
auto ic = str_ic.get();
if (unlikely(!ic)) {
ic = new CallattrIC();
str_ic.reset(ic);
}
static BoxedString* str_str = getStaticString("__str__");
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(0) };
return ic->call(obj, str_str, callattr_flags, nullptr, nullptr, nullptr, nullptr, nullptr);
}
Box* BoxedClass::callIterIC(Box* obj) {
assert(obj->cls == this);
......@@ -269,8 +284,14 @@ Box* Box::reprIC() {
return this->cls->callReprIC(this);
}
Box* Box::strIC() {
return this->cls->callStrIC(this);
}
BoxedString* Box::reprICAsString() {
Box* r = this->reprIC();
if (!r)
raiseAttributeError(this, "__repr__");
if (isSubclass(r->cls, unicode_cls)) {
r = PyUnicode_AsASCIIString(autoDecref(r));
......@@ -1506,10 +1527,13 @@ static Box* builtinFunctionOrMethodCall(BoxedBuiltinFunctionOrMethod* self, Box*
NULL);
}
extern "C" BoxedString* functionRepr(BoxedFunction* v) {
template <ExceptionStyle S> static Box* functionRepr(Box* _v) noexcept(S == CAPI) {
if (!isSubclass(_v->cls, function_cls))
return setDescrTypeError<S>(_v, "function", "__repr__");
BoxedFunction* v = (BoxedFunction*)_v;
if (!v->name)
return (BoxedString*)PyString_FromFormat("<function <name_missing?> at %p>", v);
return (BoxedString*)PyString_FromFormat("<function %s at %p>", PyString_AsString(v->name), v);
return callCAPIFromStyle<S>(PyString_FromFormat, "<function <name_missing?> at %p>", v);
return callCAPIFromStyle<S>(PyString_FromFormat, "<function %s at %p>", PyString_AsString(v->name), v);
}
static Box* functionGet(BoxedFunction* self, Box* inst, Box* owner) {
......@@ -2062,7 +2086,12 @@ extern "C" PyObject* PySlice_New(PyObject* start, PyObject* stop, PyObject* step
return createSlice(start, stop, step);
}
Box* typeRepr(BoxedClass* self) {
Box* typeRepr(Box* _self) {
if (!isSubclass(_self->cls, type_cls))
return setDescrTypeError<CXX>(_self, "type", "__repr__");
BoxedClass* self = (BoxedClass*)_self;
std::string O("");
llvm::raw_string_ostream os(O);
......@@ -2086,6 +2115,10 @@ Box* typeRepr(BoxedClass* self) {
return boxString(os.str());
}
static Box* type_repr(Box* self) noexcept {
return callCXXFromStyle<CAPI>(typeRepr, self);
}
static PyObject* type_module(Box* _type, void* context) noexcept {
PyTypeObject* type = static_cast<PyTypeObject*>(_type);
......@@ -3076,7 +3109,7 @@ static PyObject* object_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
}
static Box* type_name(Box* b, void*) noexcept;
Box* objectRepr(Box* self) {
Box* object_repr(Box* self) noexcept {
BoxedClass* type = self->cls;
DecrefHandle<Box, true> mod(NULL);
......@@ -3091,12 +3124,12 @@ Box* objectRepr(Box* self) {
}
static Box* object_str(Box* obj) noexcept {
try {
return obj->reprIC();
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
unaryfunc f;
f = Py_TYPE(obj)->tp_repr;
if (f == NULL)
f = object_repr;
return f(obj);
}
Box* objectHash(Box* obj) {
......@@ -4329,8 +4362,8 @@ void setupRuntime() {
SET = typeFromClass(set_cls);
FROZENSET = typeFromClass(frozenset_cls);
object_cls->giveAttr("__repr__",
new BoxedFunction(FunctionMetadata::create((void*)objectRepr, UNKNOWN, 1, false, false)));
object_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)object_repr, UNKNOWN, 1, false,
false, ParamNames::empty(), CAPI)));
object_cls->giveAttr("__subclasshook__",
boxInstanceMethod(object_cls, autoDecref(new BoxedFunction(FunctionMetadata::create(
(void*)objectSubclasshook, UNKNOWN, 2))),
......@@ -4369,6 +4402,7 @@ void setupRuntime() {
type_cls->freeze();
type_cls->tp_new = type_new;
type_cls->tp_repr = type_repr;
type_cls->tpp_call.capi_val = &typeTppCall<CAPI>;
type_cls->tpp_call.cxx_val = &typeTppCall<CXX>;
......@@ -4433,7 +4467,7 @@ void setupRuntime() {
{ None, None, None }));
function_cls->giveAttrBorrowed("__dict__", dict_descr);
function_cls->giveAttrDescriptor("__name__", func_name, func_set_name);
function_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)functionRepr, STR, 1)));
function_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)functionRepr<CXX>, STR, 1)));
function_cls->giveAttrMember("__module__", T_OBJECT, offsetof(BoxedFunction, modname), false);
function_cls->giveAttrMember("__doc__", T_OBJECT, offsetof(BoxedFunction, doc), false);
function_cls->giveAttrBorrowed("func_doc", function_cls->getattr(getStaticString("__doc__")));
......@@ -4453,6 +4487,7 @@ void setupRuntime() {
function_cls->giveAttrMember("func_closure", T_OBJECT, offsetof(BoxedFunction, closure), true);
function_cls->freeze();
function_cls->tp_descr_get = function_descr_get;
function_cls->tp_repr = functionRepr<CAPI>;
builtin_function_or_method_cls->giveAttrMember("__module__", T_OBJECT,
offsetof(BoxedBuiltinFunctionOrMethod, modname));
......
......@@ -185,11 +185,12 @@ public:
// Any new ics here need to get reflected in BoxedClass::dealloc
std::unique_ptr<CallattrCapiIC> next_ic;
std::unique_ptr<CallattrIC> hasnext_ic, repr_ic, iter_ic;
std::unique_ptr<CallattrIC> hasnext_ic, iter_ic, repr_ic, str_ic;
std::unique_ptr<NonzeroIC> nonzero_ic;
Box* callHasnextIC(Box* obj, bool null_on_nonexistent);
Box* call_nextIC(Box* obj) noexcept;
Box* callReprIC(Box* obj);
Box* callReprIC(Box* obj); // returns null on nonexistent!
Box* callStrIC(Box* obj); // returns null on nonexistent!
Box* callIterIC(Box* obj);
bool callNonzeroIC(Box* obj);
......@@ -478,16 +479,22 @@ template <typename B> B* xincref(B* b) {
// }
//
// since this version does not need the try-catch block when called from a CXX-style function
template <ExceptionStyle S, typename Functor> Box* callCXXFromStyle(Functor f) {
template <ExceptionStyle S, typename Functor, typename... Args> Box* callCXXFromStyle(Functor f, Args&&... args) {
if (S == CAPI) {
try {
return f();
return f(std::forward<Args>(args)...);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else
return f();
return f(std::forward<Args>(args)...);
}
template <ExceptionStyle S, typename Func, typename... Args> Box* callCAPIFromStyle(Func f, Args&&... args) {
Box* rtn = f(std::forward<Args>(args)...);
if (S == CXX && !rtn)
throwCAPIException();
return rtn;
}
// Uncoment this to disable the int freelist, which can make debugging eassier.
......
......@@ -227,7 +227,7 @@ extern "C" void dumpEx(void* p, int levels) {
}
if (PyLong_Check(b)) {
PyObject* str = longRepr(static_cast<BoxedLong*>(b));
PyObject* str = long_cls->tp_repr(b);
AUTO_DECREF(str);
printf("Long value: %s\n", static_cast<BoxedString*>(str)->c_str());
}
......
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