Commit 4e5e1dba authored by Kevin Modzelewski's avatar Kevin Modzelewski

Import more code from CPython, and add the slotdef for mp_subscript

parent 198d0f6b
......@@ -32,24 +32,160 @@ namespace pyston {
#define FLAG_SIZE_T 1
static PyObject* va_build_value(const char* fmt, va_list va, int flags) {
int len = strlen(fmt);
if (len == 0)
return None;
static int countformat(const char* format, int endchar) {
int count = 0;
int level = 0;
while (level > 0 || *format != endchar) {
switch (*format) {
case '\0':
/* Premature end */
PyErr_SetString(PyExc_SystemError, "unmatched paren in format");
return -1;
case '(':
case '[':
case '{':
if (level == 0)
count++;
level++;
break;
case ')':
case ']':
case '}':
level--;
break;
case '#':
case '&':
case ',':
case ':':
case ' ':
case '\t':
break;
default:
if (level == 0)
count++;
}
format++;
}
return count;
}
static PyObject* do_mktuple(const char**, va_list*, int, int, int) noexcept;
// static PyObject *do_mklist(const char**, va_list *, int, int, int) noexcept;
// static PyObject *do_mkdict(const char**, va_list *, int, int, int) noexcept;
static PyObject* do_mkvalue(const char**, va_list*, int) noexcept;
static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noexcept {
for (;;) {
switch (*(*p_format)++) {
case '(':
return do_mktuple(p_format, p_va, ')', countformat(*p_format, ')'), flags);
#if 0
case '[':
return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags);
case '{':
return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags);
#endif
if (len == 1) {
switch (*fmt) {
case 'b':
case 'B':
case 'h':
case 'i':
return PyInt_FromLong((long)va_arg(va, int));
return PyInt_FromLong((long)va_arg(*p_va, int));
case 'H':
return PyInt_FromLong((long)va_arg(*p_va, unsigned int));
case 'N':
case 'S':
case 'O':
if (**p_format == '&') {
typedef PyObject* (*converter)(void*);
converter func = va_arg(*p_va, converter);
void* arg = va_arg(*p_va, void*);
++*p_format;
return (*func)(arg);
} else {
PyObject* v;
v = va_arg(*p_va, PyObject*);
if (v != NULL) {
if (*(*p_format - 1) != 'N')
Py_INCREF(v);
} else if (!PyErr_Occurred())
/* If a NULL was passed
* because a call that should
* have constructed a value
* failed, that's OK, and we
* pass the error on; but if
* no error occurred it's not
* clear that the caller knew
* what she was doing. */
PyErr_SetString(PyExc_SystemError, "NULL object passed to Py_BuildValue");
return v;
}
default:
RELEASE_ASSERT(0, "%c", *fmt);
RELEASE_ASSERT(0, "%c", *((*p_format) - 1));
}
}
abort();
}
static PyObject* do_mktuple(const char** p_format, va_list* p_va, int endchar, int n, int flags) noexcept {
PyObject* v;
int i;
int itemfailed = 0;
if (n < 0)
return NULL;
if ((v = PyTuple_New(n)) == NULL)
return NULL;
/* Note that we can't bail immediately on error as this will leak
refcounts on any 'N' arguments. */
for (i = 0; i < n; i++) {
PyObject* w = do_mkvalue(p_format, p_va, flags);
if (w == NULL) {
itemfailed = 1;
Py_INCREF(Py_None);
w = Py_None;
}
PyTuple_SET_ITEM(v, i, w);
}
if (itemfailed) {
/* do_mkvalue() should have already set an error */
Py_DECREF(v);
return NULL;
}
if (**p_format != endchar) {
Py_DECREF(v);
PyErr_SetString(PyExc_SystemError, "Unmatched paren in format");
return NULL;
}
if (endchar)
++*p_format;
return v;
}
static PyObject* va_build_value(const char* fmt, va_list va, int flags) {
int n = countformat(fmt, '\0');
if (n < 0)
return NULL;
if (n == 0)
return None;
va_list lva;
__va_copy(lva, va);
if (n == 1)
return do_mkvalue(&fmt, &lva, flags);
return do_mktuple(&fmt, &lva, '\0', n, flags);
}
RELEASE_ASSERT(0, "");
extern "C" PyObject* Py_VaBuildValue(const char* format, va_list va) {
return va_build_value(format, va, 0);
}
extern "C" PyObject* _Py_BuildValue_SizeT(const char* fmt, ...) {
......
......@@ -52,6 +52,16 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) {
return (*func)(self);
}
static PyObject* wrap_binaryfunc(PyObject* self, PyObject* args, void* wrapped) {
binaryfunc func = (binaryfunc)wrapped;
PyObject* other;
if (!check_num_args(args, 1))
return NULL;
other = PyTuple_GET_ITEM(args, 0);
return (*func)(self, other);
}
static Py_ssize_t getindex(PyObject* self, PyObject* arg) noexcept {
Py_ssize_t i;
......@@ -127,6 +137,64 @@ PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
}
}
static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) {
PyObject* res;
// TODO: CPython uses the attrobj as a cache
Box* obj = typeLookup(self->cls, attrstr, NULL);
if (obj)
return processDescriptor(obj, self, self->cls);
return obj;
}
// Copied from CPython:
static PyObject* call_method(PyObject* o, const char* name, PyObject** nameobj, const char* format, ...) noexcept {
va_list va;
PyObject* args, * func = 0, *retval;
va_start(va, format);
func = lookup_maybe(o, name, nameobj);
if (func == NULL) {
va_end(va);
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_AttributeError, *nameobj);
return NULL;
}
if (format && *format)
args = Py_VaBuildValue(format, va);
else
args = PyTuple_New(0);
va_end(va);
if (args == NULL)
return NULL;
assert(PyTuple_Check(args));
retval = PyObject_Call(func, args, NULL);
Py_DECREF(args);
Py_DECREF(func);
return retval;
}
// Copied from CPython:
#define SLOT0(FUNCNAME, OPSTR) \
static PyObject* FUNCNAME(PyObject* self) noexcept { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "()"); \
}
#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \
static PyObject* FUNCNAME(PyObject* self, ARG1TYPE arg1) noexcept { \
static PyObject* cache_str; \
return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \
}
SLOT1(slot_mp_subscript, "__getitem__", PyObject*, "O")
typedef wrapper_def slotdef;
static void** slotptr(BoxedClass* type, int offset) {
......@@ -198,6 +266,8 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, wrap_binaryfunc, "x.__getitem__(y) <==> x[y]"),
// SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
The logic in abstract.c always falls back to nb_add/nb_multiply in
......
......@@ -322,7 +322,10 @@ extern "C" int PyObject_Not(PyObject* o) {
extern "C" PyObject* PyObject_Call(PyObject* callable_object, PyObject* args, PyObject* kw) {
try {
return runtimeCall(callable_object, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL);
if (kw)
return runtimeCall(callable_object, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL);
else
return runtimeCall(callable_object, ArgPassSpec(0, 0, true, false), args, NULL, NULL, NULL, NULL);
} catch (Box* b) {
Py_FatalError("unimplemented");
}
......
......@@ -142,6 +142,30 @@ call_funcs(PyObject* _module, PyObject* args) {
printf("tp_call doesnt exist\n");
}
if (cls->tp_as_mapping) {
printf("tp_as_mapping exists\n");
if (cls->tp_as_mapping->mp_subscript) {
PyObject* rtn = cls->tp_as_mapping->mp_subscript(obj, PyInt_FromLong(1));
printf("mp_subscript exists and returned\n");
Py_DECREF(rtn);
} else {
printf("mp_subscript does not exist\n");
}
} else {
printf("tp_as_mapping doesnt exist\n");
}
if (cls->tp_as_sequence) {
printf("tp_as_sequence exists\n");
if (cls->tp_as_sequence->sq_item) {
PyObject* rtn = cls->tp_as_sequence->sq_item(obj, 1);
printf("sq_item exists and returned\n");
Py_DECREF(rtn);
}
} else {
printf("tp_as_sequence doesnt exist\n");
}
Py_DECREF(obj);
Py_RETURN_NONE;
......
......@@ -14,6 +14,10 @@ class C(object):
print "__repr__()"
return "<C object>"
def __getitem__(self, idx):
print "__getitem__", idx
return idx - 5
slots_test.call_funcs(C())
# Test to make sure that updating an existing class also updates the tp_* slots:
......
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