Commit af25c3d3 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #348 from undingen/io

Add the io/_io Module and make import gzip work
parents defe96ef 4419ceb8
......@@ -292,8 +292,8 @@ STDLIB_OBJS := stdlib.bc.o stdlib.stripped.bc.o
STDLIB_RELEASE_OBJS := stdlib.release.bc.o
ASM_SRCS := $(wildcard src/runtime/*.S)
STDMODULE_SRCS := errnomodule.c shamodule.c sha256module.c sha512module.c _math.c mathmodule.c md5.c md5module.c _randommodule.c _sre.c operator.c binascii.c pwdmodule.c posixmodule.c _struct.c datetimemodule.c _functoolsmodule.c _collectionsmodule.c itertoolsmodule.c resource.c signalmodule.c selectmodule.c fcntlmodule.c timemodule.c arraymodule.c zlibmodule.c _codecsmodule.c socketmodule.c unicodedata.c _weakref.c cStringIO.c $(EXTRA_STDMODULE_SRCS)
STDOBJECT_SRCS := structseq.c capsule.c stringobject.c exceptions.c unicodeobject.c unicodectype.c bytearrayobject.c bytes_methods.c weakrefobject.c $(EXTRA_STDOBJECT_SRCS)
STDMODULE_SRCS := errnomodule.c shamodule.c sha256module.c sha512module.c _math.c mathmodule.c md5.c md5module.c _randommodule.c _sre.c operator.c binascii.c pwdmodule.c posixmodule.c _struct.c datetimemodule.c _functoolsmodule.c _collectionsmodule.c itertoolsmodule.c resource.c signalmodule.c selectmodule.c fcntlmodule.c timemodule.c arraymodule.c zlibmodule.c _codecsmodule.c socketmodule.c unicodedata.c _weakref.c cStringIO.c _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c $(EXTRA_STDMODULE_SRCS)
STDOBJECT_SRCS := structseq.c capsule.c stringobject.c exceptions.c unicodeobject.c unicodectype.c bytearrayobject.c bytes_methods.c weakrefobject.c memoryobject.c $(EXTRA_STDOBJECT_SRCS)
STDPYTHON_SRCS := pyctype.c getargs.c formatter_string.c pystrtod.c dtoa.c formatter_unicode.c structmember.c $(EXTRA_STDPYTHON_SRCS)
FROM_CPYTHON_SRCS := $(addprefix from_cpython/Modules/,$(STDMODULE_SRCS)) $(addprefix from_cpython/Objects/,$(STDOBJECT_SRCS)) $(addprefix from_cpython/Python/,$(STDPYTHON_SRCS))
......
......@@ -15,10 +15,10 @@ endforeach(STDLIB_FILE)
add_custom_target(copy_stdlib ALL DEPENDS ${STDLIB_TARGETS})
# compile specified files in from_cpython/Modules
file(GLOB_RECURSE STDMODULE_SRCS Modules errnomodule.c shamodule.c sha256module.c sha512module.c _math.c mathmodule.c md5.c md5module.c _randommodule.c _sre.c operator.c binascii.c pwdmodule.c posixmodule.c _struct.c datetimemodule.c _functoolsmodule.c _collectionsmodule.c itertoolsmodule.c resource.c signalmodule.c selectmodule.c fcntlmodule.c timemodule.c arraymodule.c zlibmodule.c _codecsmodule.c socketmodule.c unicodedata.c _weakref.c cStringIO.c)
file(GLOB_RECURSE STDMODULE_SRCS Modules errnomodule.c shamodule.c sha256module.c sha512module.c _math.c mathmodule.c md5.c md5module.c _randommodule.c _sre.c operator.c binascii.c pwdmodule.c posixmodule.c _struct.c datetimemodule.c _functoolsmodule.c _collectionsmodule.c itertoolsmodule.c resource.c signalmodule.c selectmodule.c fcntlmodule.c timemodule.c arraymodule.c zlibmodule.c _codecsmodule.c socketmodule.c unicodedata.c _weakref.c cStringIO.c bufferedio.c bytesio.c fileio.c iobase.c _iomodule.c stringio.c textio.c)
# compile specified files in from_cpython/Objects
file(GLOB_RECURSE STDOBJECT_SRCS Objects structseq.c capsule.c stringobject.c exceptions.c unicodeobject.c unicodectype.c bytearrayobject.c bytes_methods.c weakrefobject.c)
file(GLOB_RECURSE STDOBJECT_SRCS Objects structseq.c capsule.c stringobject.c exceptions.c unicodeobject.c unicodectype.c bytearrayobject.c bytes_methods.c weakrefobject.c memoryobject.c)
# compile specified files in from_cpython/Python
file(GLOB_RECURSE STDPYTHON_SRCS Python getargs.c pyctype.c formatter_string.c pystrtod.c dtoa.c formatter_unicode.c structmember.c)
......
......@@ -57,6 +57,7 @@
#ifndef WITHOUT_COMPLEX
#include "complexobject.h"
#endif
#include "memoryobject.h"
#include "stringobject.h"
#include "bufferobject.h"
#include "bytesobject.h"
......
// This file is originally from CPython 2.7, with modifications for Pyston
/* Memory view object. In Python this is available as "memoryview". */
#ifndef Py_MEMORYOBJECT_H
#define Py_MEMORYOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
PyAPI_DATA(PyTypeObject) PyMemoryView_Type;
#define PyMemoryView_Check(op) (Py_TYPE(op) == &PyMemoryView_Type)
/* Get a pointer to the underlying Py_buffer of a memoryview object. */
#define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view)
/* Get a pointer to the PyObject from which originates a memoryview object. */
#define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj)
PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base,
int buffertype,
char fort) PYSTON_NOEXCEPT;
/* Return a contiguous chunk of memory representing the buffer
from an object in a memory view object. If a copy is made then the
base object for the memory view will be a *new* bytes object.
Otherwise, the base-object will be the object itself and no
data-copying will be done.
The buffertype argument can be PyBUF_READ, PyBUF_WRITE,
PyBUF_SHADOW to determine whether the returned buffer
should be READONLY, WRITABLE, or set to update the
original buffer if a copy must be made. If buffertype is
PyBUF_WRITE and the buffer is not contiguous an error will
be raised. In this circumstance, the user can use
PyBUF_SHADOW to ensure that a a writable temporary
contiguous buffer is returned. The contents of this
contiguous buffer will be copied back into the original
object after the memoryview object is deleted as long as
the original object is writable and allows setting an
exclusive write lock. If this is not allowed by the
original object, then a BufferError is raised.
If the object is multi-dimensional and if fortran is 'F',
the first dimension of the underlying array will vary the
fastest in the buffer. If fortran is 'C', then the last
dimension will vary the fastest (C-style contiguous). If
fortran is 'A', then it does not matter and you will get
whatever the object decides is more efficient.
A new reference is returned that must be DECREF'd when finished.
*/
PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject *) PyMemoryView_FromBuffer(Py_buffer *info) PYSTON_NOEXCEPT;
/* create new if bufptr is NULL
will be a new bytesobject in base */
/* The struct is declared here so that macros can work, but it shouldn't
be considered public. Don't access those fields directly, use the macros
and functions instead! */
typedef struct {
PyObject_HEAD
PyObject *base;
Py_buffer view;
} PyMemoryViewObject;
#ifdef __cplusplus
}
#endif
#endif /* !Py_MEMORYOBJECT_H */
......@@ -27,6 +27,7 @@
#define SIZEOF_INT 4
#define SIZEOF_LONG 8
#define SIZEOF_LONG_LONG 8
#define SIZEOF_OFF_T 8
#define SIZEOF_PTHREAD_T 8
#define HAVE_COPYSIGN 1
#define HAVE_ROUND 1
......
......@@ -8,9 +8,11 @@ extern "C" {
/* The unique ellipsis object "..." */
PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
#define Py_Ellipsis (&_Py_EllipsisObject)
// Pyston change
// PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
// #define Py_Ellipsis (&_Py_EllipsisObject)
PyAPI_DATA(PyObject) *Ellipsis; /* Don't use this directly */
#define Py_Ellipsis Ellipsis
/* Slice object interface */
......
......@@ -628,10 +628,13 @@ init_io(void)
if (m == NULL)
return;
// Pyston change: we don't support importing os during init, but it looks like it works without it...
#if 0
/* put os in the module state */
_PyIO_os_module = PyImport_ImportModule("os");
if (_PyIO_os_module == NULL)
goto fail;
#endif
#define ADD_TYPE(type, name) \
if (PyType_Ready(type) < 0) \
......@@ -647,9 +650,13 @@ init_io(void)
goto fail;
/* UnsupportedOperation inherits from ValueError and IOError */
_PyIO_unsupported_operation = PyObject_CallFunction(
(PyObject *)&PyType_Type, "s(OO){}",
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
// Pyston change: during init we have to supply the module name by ourself.
_PyIO_unsupported_operation = PyObject_CallFunction((PyObject *)&PyType_Type, "s(OO){s:s}",
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError, "__module__", "io");
// _PyIO_unsupported_operation = PyObject_CallFunction(
// (PyObject *)&PyType_Type, "s(OO){}",
// "UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
if (_PyIO_unsupported_operation == NULL)
goto fail;
Py_INCREF(_PyIO_unsupported_operation);
......@@ -760,6 +767,35 @@ init_io(void)
if (!(_PyIO_zero = PyLong_FromLong(0L)))
goto fail;
// Pyston change: register with gc
// TODO: automatically register static variables as roots
PyGC_AddRoot(_PyIO_str_close);
PyGC_AddRoot(_PyIO_str_closed);
PyGC_AddRoot(_PyIO_str_decode);
PyGC_AddRoot(_PyIO_str_encode);
PyGC_AddRoot(_PyIO_str_fileno);
PyGC_AddRoot(_PyIO_str_flush);
PyGC_AddRoot(_PyIO_str_getstate);
PyGC_AddRoot(_PyIO_str_isatty);
PyGC_AddRoot(_PyIO_str_newlines);
PyGC_AddRoot(_PyIO_str_nl);
PyGC_AddRoot(_PyIO_str_read);
PyGC_AddRoot(_PyIO_str_read1);
PyGC_AddRoot(_PyIO_str_readable);
PyGC_AddRoot(_PyIO_str_readinto);
PyGC_AddRoot(_PyIO_str_readline);
PyGC_AddRoot(_PyIO_str_reset);
PyGC_AddRoot(_PyIO_str_seek);
PyGC_AddRoot(_PyIO_str_seekable);
PyGC_AddRoot(_PyIO_str_setstate);
PyGC_AddRoot(_PyIO_str_tell);
PyGC_AddRoot(_PyIO_str_truncate);
PyGC_AddRoot(_PyIO_str_writable);
PyGC_AddRoot(_PyIO_str_write);
// PyGC_AddRoot(_PyIO_empty_str); // this is already registered as root
PyGC_AddRoot(_PyIO_empty_bytes);
PyGC_AddRoot(_PyIO_zero);
return;
fail:
......
......@@ -201,10 +201,12 @@ _PyIOBase_finalize(PyObject *self)
/* If _PyIOBase_finalize() is called from a destructor, we need to
resurrect the object as calling close() can invoke arbitrary code. */
is_zombie = (Py_REFCNT(self) == 0);
if (is_zombie) {
++Py_REFCNT(self);
}
// Pyston change:
is_zombie = 0;
// is_zombie = (Py_REFCNT(self) == 0);
//if (is_zombie) {
// ++Py_REFCNT(self);
//}
PyErr_Fetch(&tp, &v, &tb);
/* If `closed` doesn't exist or can't be evaluated as bool, then the
object is probably in an unusable state, so ignore. */
......@@ -230,6 +232,8 @@ _PyIOBase_finalize(PyObject *self)
}
PyErr_Restore(tp, v, tb);
if (is_zombie) {
// Pyston change:
#if 0
if (--Py_REFCNT(self) != 0) {
/* The object lives again. The following code is taken from
slot_tp_del in typeobject.c. */
......@@ -245,12 +249,14 @@ _PyIOBase_finalize(PyObject *self)
* _Py_NewReference bumped tp_allocs: both of those need to be
* undone.
*/
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
--Py_TYPE(self)->tp_allocs;
#endif
return -1;
}
#endif
}
return 0;
}
......
......@@ -305,8 +305,9 @@ _PyIncrementalNewlineDecoder_decode(PyObject *_self,
if (!final) {
if (output_len > 0
&& PyUnicode_AS_UNICODE(output)[output_len - 1] == '\r') {
if (Py_REFCNT(output) == 1) {
// Pyston change:
// if (Py_REFCNT(output) == 1) {
if (0) {
if (PyUnicode_Resize(&output, output_len - 1) < 0)
goto error;
}
......@@ -405,7 +406,9 @@ _PyIncrementalNewlineDecoder_decode(PyObject *_self,
PyObject *translated = NULL;
Py_UNICODE *out_str;
Py_UNICODE *in, *out, *end;
if (Py_REFCNT(output) != 1) {
// Pyston change
// if (Py_REFCNT(output) != 1) {
if (1) {
/* We could try to optimize this so that we only do a copy
when there is something to translate. On the other hand,
most decoders should only output non-shared strings, i.e.
......@@ -413,7 +416,7 @@ _PyIncrementalNewlineDecoder_decode(PyObject *_self,
translated = PyUnicode_FromUnicode(NULL, len);
if (translated == NULL)
goto error;
assert(Py_REFCNT(translated) == 1);
// assert(Py_REFCNT(translated) == 1); Pyston change
memcpy(PyUnicode_AS_UNICODE(translated),
PyUnicode_AS_UNICODE(output),
len * sizeof(Py_UNICODE));
......@@ -1798,7 +1801,9 @@ _textiowrapper_readline(textio *self, Py_ssize_t limit)
/* Our line ends in the current buffer */
self->decoded_chars_used = endpos - offset_to_buffer;
if (start > 0 || endpos < PyUnicode_GET_SIZE(line)) {
if (start == 0 && Py_REFCNT(line) == 1) {
// Pyston change:
// if (start == 0 && Py_REFCNT(line) == 1) {
if (0) {
if (PyUnicode_Resize(&line, endpos) < 0)
goto error;
}
......
......@@ -892,6 +892,9 @@ finisignal(void)
int
PyErr_CheckSignals(void)
{
if (!is_tripped)
return 0;
// Pyston change:
Py_FatalError("TODO");
......@@ -899,9 +902,6 @@ PyErr_CheckSignals(void)
int i;
PyObject *f;
if (!is_tripped)
return 0;
#ifdef WITH_THREAD
if (PyThread_get_thread_ident() != main_thread)
return 0;
......
......@@ -1055,6 +1055,11 @@ PyInit_zlib(void)
PyObject *m, *ver;
Py_TYPE(&Comptype) = &PyType_Type;
Py_TYPE(&Decomptype) = &PyType_Type;
// Pyston change
PyType_Ready(&Comptype);
PyType_Ready(&Decomptype);
m = Py_InitModule4("zlib", zlib_methods,
zlib_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
......
// This file is originally from CPython 2.7, with modifications for Pyston
/* Memoryview object implementation */
#include "Python.h"
static Py_ssize_t
get_shape0(Py_buffer *buf)
{
if (buf->shape != NULL)
return buf->shape[0];
if (buf->ndim == 0)
return 1;
PyErr_SetString(PyExc_TypeError,
"exported buffer does not have any shape information associated "
"to it");
return -1;
}
static void
dup_buffer(Py_buffer *dest, Py_buffer *src)
{
*dest = *src;
if (src->ndim == 1 && src->shape != NULL) {
dest->shape = &(dest->smalltable[0]);
dest->shape[0] = get_shape0(src);
}
if (src->ndim == 1 && src->strides != NULL) {
dest->strides = &(dest->smalltable[1]);
dest->strides[0] = src->strides[0];
}
}
static int
memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
{
int res = 0;
if (self->view.obj != NULL)
res = PyObject_GetBuffer(self->view.obj, view, flags);
if (view)
dup_buffer(view, &self->view);
return res;
}
static void
memory_releasebuf(PyMemoryViewObject *self, Py_buffer *view)
{
PyBuffer_Release(view);
}
PyDoc_STRVAR(memory_doc,
"memoryview(object)\n\
\n\
Create a new memoryview object which references the given object.");
PyObject *
PyMemoryView_FromBuffer(Py_buffer *info)
{
PyMemoryViewObject *mview;
mview = (PyMemoryViewObject *)
PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
if (mview == NULL)
return NULL;
mview->base = NULL;
dup_buffer(&mview->view, info);
/* NOTE: mview->view.obj should already have been incref'ed as
part of PyBuffer_FillInfo(). */
_PyObject_GC_TRACK(mview);
return (PyObject *)mview;
}
PyObject *
PyMemoryView_FromObject(PyObject *base)
{
PyMemoryViewObject *mview;
Py_buffer view;
if (!PyObject_CheckBuffer(base)) {
PyErr_SetString(PyExc_TypeError,
"cannot make memory view because object does "
"not have the buffer interface");
return NULL;
}
if (PyObject_GetBuffer(base, &view, PyBUF_FULL_RO) < 0)
return NULL;
mview = (PyMemoryViewObject *)PyMemoryView_FromBuffer(&view);
if (mview == NULL) {
PyBuffer_Release(&view);
return NULL;
}
mview->base = base;
Py_INCREF(base);
return (PyObject *)mview;
}
static PyObject *
memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
PyObject *obj;
static char *kwlist[] = {"object", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist,
&obj)) {
return NULL;
}
return PyMemoryView_FromObject(obj);
}
static void
_strided_copy_nd(char *dest, char *src, int nd, Py_ssize_t *shape,
Py_ssize_t *strides, Py_ssize_t itemsize, char fort)
{
int k;
Py_ssize_t outstride;
if (nd==0) {
memcpy(dest, src, itemsize);
}
else if (nd == 1) {
for (k = 0; k<shape[0]; k++) {
memcpy(dest, src, itemsize);
dest += itemsize;
src += strides[0];
}
}
else {
if (fort == 'F') {
/* Copy first dimension first,
second dimension second, etc...
Set up the recursive loop backwards so that final
dimension is actually copied last.
*/
outstride = itemsize;
for (k=1; k<nd-1;k++) {
outstride *= shape[k];
}
for (k=0; k<shape[nd-1]; k++) {
_strided_copy_nd(dest, src, nd-1, shape,
strides, itemsize, fort);
dest += outstride;
src += strides[nd-1];
}
}
else {
/* Copy last dimension first,
second-to-last dimension second, etc.
Set up the recursion so that the
first dimension is copied last
*/
outstride = itemsize;
for (k=1; k < nd; k++) {
outstride *= shape[k];
}
for (k=0; k<shape[0]; k++) {
_strided_copy_nd(dest, src, nd-1, shape+1,
strides+1, itemsize,
fort);
dest += outstride;
src += strides[0];
}
}
}
return;
}
static int
_indirect_copy_nd(char *dest, Py_buffer *view, char fort)
{
Py_ssize_t *indices;
int k;
Py_ssize_t elements;
char *ptr;
void (*func)(int, Py_ssize_t *, const Py_ssize_t *);
if (view->ndim > PY_SSIZE_T_MAX / sizeof(Py_ssize_t)) {
PyErr_NoMemory();
return -1;
}
indices = (Py_ssize_t *)PyMem_Malloc(sizeof(Py_ssize_t)*view->ndim);
if (indices == NULL) {
PyErr_NoMemory();
return -1;
}
for (k=0; k<view->ndim;k++) {
indices[k] = 0;
}
elements = 1;
for (k=0; k<view->ndim; k++) {
elements *= view->shape[k];
}
if (fort == 'F') {
func = _Py_add_one_to_index_F;
}
else {
func = _Py_add_one_to_index_C;
}
while (elements--) {
func(view->ndim, indices, view->shape);
ptr = PyBuffer_GetPointer(view, indices);
memcpy(dest, ptr, view->itemsize);
dest += view->itemsize;
}
PyMem_Free(indices);
return 0;
}
/*
Get a the data from an object as a contiguous chunk of memory (in
either 'C' or 'F'ortran order) even if it means copying it into a
separate memory area.
Returns a new reference to a Memory view object. If no copy is needed,
the memory view object points to the original memory and holds a
lock on the original. If a copy is needed, then the memory view object
points to a brand-new Bytes object (and holds a memory lock on it).
buffertype
PyBUF_READ buffer only needs to be read-only
PyBUF_WRITE buffer needs to be writable (give error if not contiguous)
PyBUF_SHADOW buffer needs to be writable so shadow it with
a contiguous buffer if it is not. The view will point to
the shadow buffer which can be written to and then
will be copied back into the other buffer when the memory
view is de-allocated. While the shadow buffer is
being used, it will have an exclusive write lock on
the original buffer.
*/
PyObject *
PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char fort)
{
PyMemoryViewObject *mem;
PyObject *bytes;
Py_buffer *view;
int flags;
char *dest;
if (!PyObject_CheckBuffer(obj)) {
PyErr_SetString(PyExc_TypeError,
"object does not have the buffer interface");
return NULL;
}
mem = PyObject_GC_New(PyMemoryViewObject, &PyMemoryView_Type);
if (mem == NULL)
return NULL;
view = &mem->view;
flags = PyBUF_FULL_RO;
switch(buffertype) {
case PyBUF_WRITE:
flags = PyBUF_FULL;
break;
}
if (PyObject_GetBuffer(obj, view, flags) != 0) {
Py_DECREF(mem);
return NULL;
}
if (PyBuffer_IsContiguous(view, fort)) {
/* no copy needed */
Py_INCREF(obj);
mem->base = obj;
_PyObject_GC_TRACK(mem);
return (PyObject *)mem;
}
/* otherwise a copy is needed */
if (buffertype == PyBUF_WRITE) {
Py_DECREF(mem);
PyErr_SetString(PyExc_BufferError,
"writable contiguous buffer requested "
"for a non-contiguousobject.");
return NULL;
}
bytes = PyBytes_FromStringAndSize(NULL, view->len);
if (bytes == NULL) {
Py_DECREF(mem);
return NULL;
}
dest = PyBytes_AS_STRING(bytes);
/* different copying strategy depending on whether
or not any pointer de-referencing is needed
*/
/* strided or in-direct copy */
if (view->suboffsets==NULL) {
_strided_copy_nd(dest, view->buf, view->ndim, view->shape,
view->strides, view->itemsize, fort);
}
else {
if (_indirect_copy_nd(dest, view, fort) < 0) {
Py_DECREF(bytes);
Py_DECREF(mem);
return NULL;
}
}
if (buffertype == PyBUF_SHADOW) {
/* return a shadowed memory-view object */
view->buf = dest;
mem->base = PyTuple_Pack(2, obj, bytes);
Py_DECREF(bytes);
if (mem->base == NULL) {
Py_DECREF(mem);
return NULL;
}
}
else {
PyBuffer_Release(view); /* XXX ? */
/* steal the reference */
mem->base = bytes;
}
_PyObject_GC_TRACK(mem);
return (PyObject *)mem;
}
static PyObject *
memory_format_get(PyMemoryViewObject *self)
{
return PyString_FromString(self->view.format);
}
static PyObject *
memory_itemsize_get(PyMemoryViewObject *self)
{
return PyLong_FromSsize_t(self->view.itemsize);
}
static PyObject *
_IntTupleFromSsizet(int len, Py_ssize_t *vals)
{
int i;
PyObject *o;
PyObject *intTuple;
if (vals == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
intTuple = PyTuple_New(len);
if (!intTuple) return NULL;
for(i=0; i<len; i++) {
o = PyLong_FromSsize_t(vals[i]);
if (!o) {
Py_DECREF(intTuple);
return NULL;
}
PyTuple_SET_ITEM(intTuple, i, o);
}
return intTuple;
}
static PyObject *
memory_shape_get(PyMemoryViewObject *self)
{
return _IntTupleFromSsizet(self->view.ndim, self->view.shape);
}
static PyObject *
memory_strides_get(PyMemoryViewObject *self)
{
return _IntTupleFromSsizet(self->view.ndim, self->view.strides);
}
static PyObject *
memory_suboffsets_get(PyMemoryViewObject *self)
{
return _IntTupleFromSsizet(self->view.ndim, self->view.suboffsets);
}
static PyObject *
memory_readonly_get(PyMemoryViewObject *self)
{
return PyBool_FromLong(self->view.readonly);
}
static PyObject *
memory_ndim_get(PyMemoryViewObject *self)
{
return PyLong_FromLong(self->view.ndim);
}
static PyGetSetDef memory_getsetlist[] ={
{"format", (getter)memory_format_get, NULL, NULL},
{"itemsize", (getter)memory_itemsize_get, NULL, NULL},
{"shape", (getter)memory_shape_get, NULL, NULL},
{"strides", (getter)memory_strides_get, NULL, NULL},
{"suboffsets", (getter)memory_suboffsets_get, NULL, NULL},
{"readonly", (getter)memory_readonly_get, NULL, NULL},
{"ndim", (getter)memory_ndim_get, NULL, NULL},
{NULL, NULL, NULL, NULL},
};
static PyObject *
memory_tobytes(PyMemoryViewObject *self, PyObject *noargs)
{
Py_buffer view;
PyObject *res;
if (PyObject_GetBuffer((PyObject *)self, &view, PyBUF_SIMPLE) < 0)
return NULL;
res = PyBytes_FromStringAndSize(NULL, view.len);
PyBuffer_ToContiguous(PyBytes_AS_STRING(res), &view, view.len, 'C');
PyBuffer_Release(&view);
return res;
}
/* TODO: rewrite this function using the struct module to unpack
each buffer item */
static PyObject *
memory_tolist(PyMemoryViewObject *mem, PyObject *noargs)
{
Py_buffer *view = &(mem->view);
Py_ssize_t i;
PyObject *res, *item;
char *buf;
if (strcmp(view->format, "B") || view->itemsize != 1) {
PyErr_SetString(PyExc_NotImplementedError,
"tolist() only supports byte views");
return NULL;
}
if (view->ndim != 1) {
PyErr_SetString(PyExc_NotImplementedError,
"tolist() only supports one-dimensional objects");
return NULL;
}
res = PyList_New(view->len);
if (res == NULL)
return NULL;
buf = view->buf;
for (i = 0; i < view->len; i++) {
item = PyInt_FromLong((unsigned char) *buf);
if (item == NULL) {
Py_DECREF(res);
return NULL;
}
PyList_SET_ITEM(res, i, item);
buf++;
}
return res;
}
static PyMethodDef memory_methods[] = {
{"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, NULL},
{"tolist", (PyCFunction)memory_tolist, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};
static void
memory_dealloc(PyMemoryViewObject *self)
{
_PyObject_GC_UNTRACK(self);
if (self->view.obj != NULL) {
if (self->base && PyTuple_Check(self->base)) {
/* Special case when first element is generic object
with buffer interface and the second element is a
contiguous "shadow" that must be copied back into
the data areay of the first tuple element before
releasing the buffer on the first element.
*/
PyObject_CopyData(PyTuple_GET_ITEM(self->base,0),
PyTuple_GET_ITEM(self->base,1));
/* The view member should have readonly == -1 in
this instance indicating that the memory can
be "locked" and was locked and will be unlocked
again after this call.
*/
PyBuffer_Release(&(self->view));
}
else {
PyBuffer_Release(&(self->view));
}
Py_CLEAR(self->base);
}
PyObject_GC_Del(self);
}
static PyObject *
memory_repr(PyMemoryViewObject *self)
{
return PyString_FromFormat("<memory at %p>", self);
}
/* Sequence methods */
static Py_ssize_t
memory_length(PyMemoryViewObject *self)
{
return get_shape0(&self->view);
}
/* Alternate version of memory_subcript that only accepts indices.
Used by PySeqIter_New().
*/
static PyObject *
memory_item(PyMemoryViewObject *self, Py_ssize_t result)
{
Py_buffer *view = &(self->view);
if (view->ndim == 0) {
PyErr_SetString(PyExc_IndexError,
"invalid indexing of 0-dim memory");
return NULL;
}
if (view->ndim == 1) {
/* Return a bytes object */
char *ptr;
ptr = (char *)view->buf;
if (result < 0) {
result += get_shape0(view);
}
if ((result < 0) || (result >= get_shape0(view))) {
PyErr_SetString(PyExc_IndexError,
"index out of bounds");
return NULL;
}
if (view->strides == NULL)
ptr += view->itemsize * result;
else
ptr += view->strides[0] * result;
if (view->suboffsets != NULL &&
view->suboffsets[0] >= 0) {
ptr = *((char **)ptr) + view->suboffsets[0];
}
return PyBytes_FromStringAndSize(ptr, view->itemsize);
} else {
/* Return a new memory-view object */
Py_buffer newview;
memset(&newview, 0, sizeof(newview));
/* XXX: This needs to be fixed so it actually returns a sub-view */
return PyMemoryView_FromBuffer(&newview);
}
}
/*
mem[obj] returns a bytes object holding the data for one element if
obj fully indexes the memory view or another memory-view object
if it does not.
0-d memory-view objects can be referenced using ... or () but
not with anything else.
*/
static PyObject *
memory_subscript(PyMemoryViewObject *self, PyObject *key)
{
Py_buffer *view;
view = &(self->view);
if (view->ndim == 0) {
if (key == Py_Ellipsis ||
(PyTuple_Check(key) && PyTuple_GET_SIZE(key)==0)) {
Py_INCREF(self);
return (PyObject *)self;
}
else {
PyErr_SetString(PyExc_IndexError,
"invalid indexing of 0-dim memory");
return NULL;
}
}
if (PyIndex_Check(key)) {
Py_ssize_t result;
result = PyNumber_AsSsize_t(key, NULL);
if (result == -1 && PyErr_Occurred())
return NULL;
return memory_item(self, result);
}
else if (PySlice_Check(key)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
&start, &stop, &step, &slicelength) < 0) {
return NULL;
}
if (step == 1 && view->ndim == 1) {
Py_buffer newview;
void *newbuf = (char *) view->buf
+ start * view->itemsize;
int newflags = view->readonly
? PyBUF_CONTIG_RO : PyBUF_CONTIG;
/* XXX There should be an API to create a subbuffer */
if (view->obj != NULL) {
if (PyObject_GetBuffer(view->obj, &newview, newflags) == -1)
return NULL;
}
else {
newview = *view;
}
newview.buf = newbuf;
newview.len = slicelength * newview.itemsize;
newview.format = view->format;
newview.shape = &(newview.smalltable[0]);
newview.shape[0] = slicelength;
newview.strides = &(newview.itemsize);
return PyMemoryView_FromBuffer(&newview);
}
PyErr_SetNone(PyExc_NotImplementedError);
return NULL;
}
PyErr_Format(PyExc_TypeError,
"cannot index memory using \"%.200s\"",
key->ob_type->tp_name);
return NULL;
}
/* Need to support assigning memory if we can */
static int
memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value)
{
Py_ssize_t start, len, bytelen;
Py_buffer srcview;
Py_buffer *view = &(self->view);
char *srcbuf, *destbuf;
if (view->readonly) {
PyErr_SetString(PyExc_TypeError,
"cannot modify read-only memory");
return -1;
}
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"cannot delete memory");
return -1;
}
if (view->ndim != 1) {
PyErr_SetNone(PyExc_NotImplementedError);
return -1;
}
if (PyIndex_Check(key)) {
start = PyNumber_AsSsize_t(key, NULL);
if (start == -1 && PyErr_Occurred())
return -1;
if (start < 0) {
start += get_shape0(view);
}
if ((start < 0) || (start >= get_shape0(view))) {
PyErr_SetString(PyExc_IndexError,
"index out of bounds");
return -1;
}
len = 1;
}
else if (PySlice_Check(key)) {
Py_ssize_t stop, step;
if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view),
&start, &stop, &step, &len) < 0) {
return -1;
}
if (step != 1) {
PyErr_SetNone(PyExc_NotImplementedError);
return -1;
}
}
else {
PyErr_Format(PyExc_TypeError,
"cannot index memory using \"%.200s\"",
key->ob_type->tp_name);
return -1;
}
if (PyObject_GetBuffer(value, &srcview, PyBUF_CONTIG_RO) == -1) {
return -1;
}
/* XXX should we allow assignment of different item sizes
as long as the byte length is the same?
(e.g. assign 2 shorts to a 4-byte slice) */
if (srcview.itemsize != view->itemsize) {
PyErr_Format(PyExc_TypeError,
"mismatching item sizes for \"%.200s\" and \"%.200s\"",
view->obj->ob_type->tp_name, srcview.obj->ob_type->tp_name);
goto _error;
}
bytelen = len * view->itemsize;
if (bytelen != srcview.len) {
PyErr_SetString(PyExc_ValueError,
"cannot modify size of memoryview object");
goto _error;
}
/* Do the actual copy */
destbuf = (char *) view->buf + start * view->itemsize;
srcbuf = (char *) srcview.buf;
if (destbuf + bytelen < srcbuf || srcbuf + bytelen < destbuf)
/* No overlapping */
memcpy(destbuf, srcbuf, bytelen);
else
memmove(destbuf, srcbuf, bytelen);
PyBuffer_Release(&srcview);
return 0;
_error:
PyBuffer_Release(&srcview);
return -1;
}
static PyObject *
memory_richcompare(PyObject *v, PyObject *w, int op)
{
Py_buffer vv, ww;
int equal = 0;
PyObject *res;
vv.obj = NULL;
ww.obj = NULL;
if (op != Py_EQ && op != Py_NE)
goto _notimpl;
if (PyObject_GetBuffer(v, &vv, PyBUF_CONTIG_RO) == -1) {
PyErr_Clear();
goto _notimpl;
}
if (PyObject_GetBuffer(w, &ww, PyBUF_CONTIG_RO) == -1) {
PyErr_Clear();
goto _notimpl;
}
if (vv.itemsize != ww.itemsize || vv.len != ww.len)
goto _end;
equal = !memcmp(vv.buf, ww.buf, vv.len);
_end:
PyBuffer_Release(&vv);
PyBuffer_Release(&ww);
if ((equal && op == Py_EQ) || (!equal && op == Py_NE))
res = Py_True;
else
res = Py_False;
Py_INCREF(res);
return res;
_notimpl:
PyBuffer_Release(&vv);
PyBuffer_Release(&ww);
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
static int
memory_traverse(PyMemoryViewObject *self, visitproc visit, void *arg)
{
if (self->base != NULL)
Py_VISIT(self->base);
if (self->view.obj != NULL)
Py_VISIT(self->view.obj);
return 0;
}
static int
memory_clear(PyMemoryViewObject *self)
{
Py_CLEAR(self->base);
PyBuffer_Release(&self->view);
return 0;
}
/* As mapping */
static PyMappingMethods memory_as_mapping = {
(lenfunc)memory_length, /* mp_length */
(binaryfunc)memory_subscript, /* mp_subscript */
(objobjargproc)memory_ass_sub, /* mp_ass_subscript */
};
static PySequenceMethods memory_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
(ssizeargfunc)memory_item, /* sq_item */
};
/* Buffer methods */
static PyBufferProcs memory_as_buffer = {
0, /* bf_getreadbuffer */
0, /* bf_getwritebuffer */
0, /* bf_getsegcount */
0, /* bf_getcharbuffer */
(getbufferproc)memory_getbuf, /* bf_getbuffer */
(releasebufferproc)memory_releasebuf, /* bf_releasebuffer */
};
PyTypeObject PyMemoryView_Type = {
// Pyston change
//PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyVarObject_HEAD_INIT(NULL, 0)
"memoryview",
sizeof(PyMemoryViewObject),
0,
(destructor)memory_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)memory_repr, /* tp_repr */
0, /* tp_as_number */
&memory_as_sequence, /* tp_as_sequence */
&memory_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&memory_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
memory_doc, /* tp_doc */
(traverseproc)memory_traverse, /* tp_traverse */
(inquiry)memory_clear, /* tp_clear */
memory_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
memory_methods, /* tp_methods */
0, /* tp_members */
memory_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
memory_new, /* tp_new */
};
......@@ -31,10 +31,120 @@ extern "C" Py_ssize_t _PyObject_LengthHint(PyObject* o, Py_ssize_t defaultvalue)
Py_FatalError("unimplemented");
}
static int _IsFortranContiguous(Py_buffer* view) {
Py_ssize_t sd, dim;
int i;
if (view->ndim == 0)
return 1;
if (view->strides == NULL)
return (view->ndim == 1);
sd = view->itemsize;
if (view->ndim == 1)
return (view->shape[0] == 1 || sd == view->strides[0]);
for (i = 0; i < view->ndim; i++) {
dim = view->shape[i];
if (dim == 0)
return 1;
if (view->strides[i] != sd)
return 0;
sd *= dim;
}
return 1;
}
static int _IsCContiguous(Py_buffer* view) {
Py_ssize_t sd, dim;
int i;
if (view->ndim == 0)
return 1;
if (view->strides == NULL)
return 1;
sd = view->itemsize;
if (view->ndim == 1)
return (view->shape[0] == 1 || sd == view->strides[0]);
for (i = view->ndim - 1; i >= 0; i--) {
dim = view->shape[i];
if (dim == 0)
return 1;
if (view->strides[i] != sd)
return 0;
sd *= dim;
}
return 1;
}
extern "C" int PyBuffer_IsContiguous(Py_buffer* view, char fort) noexcept {
if (view->suboffsets != NULL)
return 0;
if (fort == 'C')
return _IsCContiguous(view);
else if (fort == 'F')
return _IsFortranContiguous(view);
else if (fort == 'A')
return (_IsCContiguous(view) || _IsFortranContiguous(view));
return 0;
}
extern "C" int PyBuffer_ToContiguous(void* buf, Py_buffer* view, Py_ssize_t len, char fort) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyBuffer_FillInfo(Py_buffer* view, PyObject* obj, void* buf, Py_ssize_t len, int readonly,
int flags) noexcept {
if (view == NULL)
return 0;
if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (readonly == 1)) {
// Don't support PyErr_SetString yet:
assert(0);
// PyErr_SetString(PyExc_BufferError, "Object is not writable.");
// return -1;
}
view->obj = obj;
if (obj)
Py_INCREF(obj);
view->buf = buf;
view->len = len;
view->readonly = readonly;
view->itemsize = 1;
view->format = NULL;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = "B";
view->ndim = 1;
view->shape = NULL;
if ((flags & PyBUF_ND) == PyBUF_ND)
view->shape = &(view->len);
view->strides = NULL;
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
view->strides = &(view->itemsize);
view->suboffsets = NULL;
view->internal = NULL;
return 0;
}
extern "C" void PyBuffer_Release(Py_buffer* view) noexcept {
if (!view->buf) {
assert(!view->obj);
return;
}
PyObject* obj = view->obj;
if (obj) {
assert(obj->cls == str_cls);
if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer)
Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view);
Py_XDECREF(obj);
}
view->obj = NULL;
}
static PyObject* type_error(const char* msg, PyObject* obj) noexcept {
PyErr_Format(PyExc_TypeError, msg, Py_TYPE(obj)->tp_name);
return NULL;
......@@ -309,6 +419,32 @@ extern "C" PyObject* PyObject_CallObject(PyObject* obj, PyObject* args) noexcept
}
}
extern "C" int PyObject_AsCharBuffer(PyObject* obj, const char** buffer, Py_ssize_t* buffer_len) noexcept {
PyBufferProcs* pb;
char* pp;
Py_ssize_t len;
if (obj == NULL || buffer == NULL || buffer_len == NULL) {
null_error();
return -1;
}
pb = obj->cls->tp_as_buffer;
if (pb == NULL || pb->bf_getcharbuffer == NULL || pb->bf_getsegcount == NULL) {
PyErr_SetString(PyExc_TypeError, "expected a character buffer object");
return -1;
}
if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
PyErr_SetString(PyExc_TypeError, "expected a single-segment buffer object");
return -1;
}
len = (*pb->bf_getcharbuffer)(obj, 0, &pp);
if (len < 0)
return -1;
*buffer = pp;
*buffer_len = len;
return 0;
}
extern "C" int PyObject_AsReadBuffer(PyObject* obj, const void** buffer, Py_ssize_t* buffer_len) noexcept {
Py_FatalError("unimplemented");
}
......@@ -341,6 +477,33 @@ extern "C" PyObject* PyObject_CallMethod(PyObject* o, const char* name, const ch
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyObject_CallMethodObjArgs(PyObject* callable, PyObject* name, ...) noexcept {
PyObject* args, *tmp;
va_list vargs;
if (callable == NULL || name == NULL)
return null_error();
callable = PyObject_GetAttr(callable, name);
if (callable == NULL)
return NULL;
/* count the args */
va_start(vargs, name);
args = objargs_mktuple(vargs);
va_end(vargs);
if (args == NULL) {
Py_DECREF(callable);
return NULL;
}
tmp = PyObject_Call(callable, args, NULL);
Py_DECREF(args);
Py_DECREF(callable);
return tmp;
}
extern "C" PyObject* _PyObject_CallMethod_SizeT(PyObject* o, const char* name, const char* format, ...) noexcept {
// TODO it looks like this could be made much more efficient by calling our callattr(), but
// I haven't taken the time to verify that that has the same behavior
......@@ -550,6 +713,110 @@ extern "C" PyObject* PySequence_Fast(PyObject* v, const char* m) noexcept {
return v;
}
extern "C" void* PyBuffer_GetPointer(Py_buffer* view, Py_ssize_t* indices) noexcept {
char* pointer;
int i;
pointer = (char*)view->buf;
for (i = 0; i < view->ndim; i++) {
pointer += view->strides[i] * indices[i];
if ((view->suboffsets != NULL) && (view->suboffsets[i] >= 0)) {
pointer = *((char**)pointer) + view->suboffsets[i];
}
}
return (void*)pointer;
}
extern "C" void _Py_add_one_to_index_F(int nd, Py_ssize_t* index, const Py_ssize_t* shape) noexcept {
int k;
for (k = 0; k < nd; k++) {
if (index[k] < shape[k] - 1) {
index[k]++;
break;
} else {
index[k] = 0;
}
}
}
extern "C" void _Py_add_one_to_index_C(int nd, Py_ssize_t* index, const Py_ssize_t* shape) noexcept {
int k;
for (k = nd - 1; k >= 0; k--) {
if (index[k] < shape[k] - 1) {
index[k]++;
break;
} else {
index[k] = 0;
}
}
}
extern "C" int PyObject_CopyData(PyObject* dest, PyObject* src) noexcept {
Py_buffer view_dest, view_src;
int k;
Py_ssize_t* indices, elements;
char* dptr, *sptr;
if (!PyObject_CheckBuffer(dest) || !PyObject_CheckBuffer(src)) {
PyErr_SetString(PyExc_TypeError, "both destination and source must have the "
"buffer interface");
return -1;
}
if (PyObject_GetBuffer(dest, &view_dest, PyBUF_FULL) != 0)
return -1;
if (PyObject_GetBuffer(src, &view_src, PyBUF_FULL_RO) != 0) {
PyBuffer_Release(&view_dest);
return -1;
}
if (view_dest.len < view_src.len) {
PyErr_SetString(PyExc_BufferError, "destination is too small to receive data from source");
PyBuffer_Release(&view_dest);
PyBuffer_Release(&view_src);
return -1;
}
if ((PyBuffer_IsContiguous(&view_dest, 'C') && PyBuffer_IsContiguous(&view_src, 'C'))
|| (PyBuffer_IsContiguous(&view_dest, 'F') && PyBuffer_IsContiguous(&view_src, 'F'))) {
/* simplest copy is all that is needed */
memcpy(view_dest.buf, view_src.buf, view_src.len);
PyBuffer_Release(&view_dest);
PyBuffer_Release(&view_src);
return 0;
}
/* Otherwise a more elaborate copy scheme is needed */
/* XXX(nnorwitz): need to check for overflow! */
indices = (Py_ssize_t*)PyMem_Malloc(sizeof(Py_ssize_t) * view_src.ndim);
if (indices == NULL) {
PyErr_NoMemory();
PyBuffer_Release(&view_dest);
PyBuffer_Release(&view_src);
return -1;
}
for (k = 0; k < view_src.ndim; k++) {
indices[k] = 0;
}
elements = 1;
for (k = 0; k < view_src.ndim; k++) {
/* XXX(nnorwitz): can this overflow? */
elements *= view_src.shape[k];
}
while (elements--) {
_Py_add_one_to_index_C(view_src.ndim, indices, view_src.shape);
dptr = (char*)PyBuffer_GetPointer(&view_dest, indices);
sptr = (char*)PyBuffer_GetPointer(&view_src, indices);
memcpy(dptr, sptr, view_src.itemsize);
}
PyMem_Free(indices);
PyBuffer_Release(&view_dest);
PyBuffer_Release(&view_src);
return 0;
}
static PyObject* binary_op1(PyObject* v, PyObject* w, const int op_slot) {
PyObject* x;
binaryfunc slotv = NULL;
......@@ -666,7 +933,20 @@ extern "C" PyObject* PySequence_List(PyObject* v) noexcept {
}
extern "C" PyObject* PyObject_CallFunction(PyObject* callable, const char* format, ...) noexcept {
Py_FatalError("unimplemented");
va_list va;
PyObject* args;
if (callable == NULL)
return null_error();
if (format && *format) {
va_start(va, format);
args = Py_VaBuildValue(format, va);
va_end(va);
} else
args = PyTuple_New(0);
return call_function_tail(callable, args);
}
extern "C" int PyMapping_Check(PyObject* o) noexcept {
......@@ -708,4 +988,285 @@ extern "C" PyObject* PyMapping_GetItemString(PyObject* o, char* key) noexcept {
extern "C" int PyMapping_SetItemString(PyObject* o, char* key, PyObject* v) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyNumber_Check(PyObject* obj) noexcept {
assert(obj && obj->cls);
// Our check, since we don't currently fill in tp_as_number:
if (isSubclass(obj->cls, int_cls) || isSubclass(obj->cls, long_cls))
return true;
// The CPython check:
return obj->cls->tp_as_number && (obj->cls->tp_as_number->nb_int || obj->cls->tp_as_number->nb_float);
}
extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Add);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" PyObject* PyNumber_Subtract(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Sub);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Multiply(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mult);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Divide(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Div);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_FloorDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_TrueDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Remainder(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mod);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Divmod(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Positive(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Absolute(PyObject* o) noexcept {
try {
return abs_(o);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Lshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::RShift);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::BitAnd);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Xor(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Or(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceSubtract(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceMultiply(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceFloorDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceTrueDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceRemainder(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlacePower(PyObject*, PyObject*, PyObject* o3) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceLshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceRshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceAnd(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceXor(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceOr(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyNumber_Coerce(PyObject**, PyObject**) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyNumber_CoerceEx(PyObject**, PyObject**) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Int(PyObject* o) noexcept {
PyNumberMethods* m;
const char* buffer;
Py_ssize_t buffer_len;
if (o == NULL) {
PyErr_SetString(PyExc_SystemError, "null argument to internal routing");
return NULL;
}
if (PyInt_CheckExact(o)) {
Py_INCREF(o);
return o;
}
m = o->cls->tp_as_number;
if (m && m->nb_int) { /* This should include subclasses of int */
/* Classic classes always take this branch. */
PyObject* res = m->nb_int(o);
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
PyErr_Format(PyExc_TypeError, "__int__ returned non-int (type %.200s)", res->cls->tp_name);
Py_DECREF(res);
return NULL;
}
return res;
}
if (PyInt_Check(o)) { /* A int subclass without nb_int */
BoxedInt* io = (BoxedInt*)o;
return PyInt_FromLong(io->n);
}
Py_FatalError("unimplemented __trunc__ and string -> int conversion");
// the remainder of PyNumber_Int deals with __trunc__ usage, and converting from unicode/string to int
#if 0
PyObject* trunc_func = getattr(o, "__trunc__");
if (trunc_func) {
PyObject *truncated = PyEval_CallObject(trunc_func, NULL);
Py_DECREF(trunc_func);
/* __trunc__ is specified to return an Integral type, but
int() needs to return an int. */
return _PyNumber_ConvertIntegralToInt(
truncated,
"__trunc__ returned non-Integral (type %.200s)");
}
PyErr_Clear(); /* It's not an error if o.__trunc__ doesn't exist. */
if (PyString_Check(o))
return int_from_string(PyString_AS_STRING(o),
PyString_GET_SIZE(o));
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(o))
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(o),
PyUnicode_GET_SIZE(o),
10);
#endif
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
return int_from_string((char*)buffer, buffer_len);
return type_error("int() argument must be a string or a "
"number, not '%.200s'", o);
#endif
}
extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept {
// This method should do quite a bit more, including checking tp_as_number->nb_long or calling __trunc__
if (o->cls == long_cls)
return o;
if (o->cls == float_cls)
return PyLong_FromDouble(PyFloat_AsDouble(o));
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept {
PyObject* result = NULL;
if (o == NULL)
return null_error();
if (PyInt_Check(o) || PyLong_Check(o)) {
return o;
}
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
Py_FatalError("unimplemented");
}
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);
}
Py_FatalError("unimplemented");
}
}
......@@ -83,7 +83,7 @@ static int _ustrlen(Py_UNICODE* u) {
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_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 {
......@@ -95,10 +95,8 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
case '[':
return do_mklist(p_format, p_va, ']', countformat(*p_format, ']'), flags);
#if 0
case '{':
return do_mkdict(p_format, p_va, '}', countformat(*p_format, '}'), flags);
#endif
case 'b':
case 'B':
......@@ -198,6 +196,13 @@ static PyObject* do_mkvalue(const char** p_format, va_list* p_va, int flags) noe
return v;
}
#endif
case ':':
case ',':
case ' ':
case '\t':
break;
default:
RELEASE_ASSERT(0, "%c", *((*p_format) - 1));
}
......@@ -239,6 +244,48 @@ static PyObject* do_mktuple(const char** p_format, va_list* p_va, int endchar, i
return v;
}
static PyObject* do_mkdict(const char** p_format, va_list* p_va, int endchar, int n, int flags) noexcept {
PyObject* d;
int i;
int itemfailed = 0;
if (n < 0)
return NULL;
if ((d = PyDict_New()) == 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 += 2) {
PyObject* k, *v;
int err;
k = do_mkvalue(p_format, p_va, flags);
if (k == NULL) {
itemfailed = 1;
Py_INCREF(Py_None);
k = Py_None;
}
v = do_mkvalue(p_format, p_va, flags);
if (v == NULL) {
itemfailed = 1;
Py_INCREF(Py_None);
v = Py_None;
}
err = PyDict_SetItem(d, k, v);
Py_DECREF(k);
Py_DECREF(v);
if (err < 0 || itemfailed) {
Py_DECREF(d);
return NULL;
}
}
if (d != NULL && **p_format != endchar) {
Py_DECREF(d);
d = NULL;
PyErr_SetString(PyExc_SystemError, "Unmatched paren in format");
} else if (endchar)
++*p_format;
return d;
}
static PyObject* do_mklist(const char** p_format, va_list* p_va, int endchar, int n, int flags) noexcept {
PyObject* v;
int i;
......
......@@ -151,6 +151,16 @@ extern "C" int PyObject_SetAttr(PyObject* v, PyObject* name, PyObject* value) no
Py_FatalError("unimplemented");
}
extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w) noexcept {
try {
setattr(v, name, w);
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
return 0;
}
extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept {
// TODO do something like this? not sure if this is safe; will people expect that calling into a known function
// won't end up doing a GIL check?
......
......@@ -2315,7 +2315,8 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, "");
RELEASE_ASSERT(cls->tp_setattro == NULL || cls->tp_setattro == PyObject_GenericSetAttr, "");
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES;
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES
| Py_TPFLAGS_HAVE_NEWBUFFER;
RELEASE_ASSERT((cls->tp_flags & ~ALLOWABLE_FLAGS) == 0, "");
if (cls->tp_as_number) {
RELEASE_ASSERT(cls->tp_flags & Py_TPFLAGS_CHECKTYPES, "Pyston doesn't yet support non-checktypes behavior");
......
......@@ -44,6 +44,8 @@
namespace pyston {
extern "C" {
Box* Ellipsis = 0;
// Copied from CPython:
#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T)
const char* Py_FileSystemDefaultEncoding = "mbcs";
......@@ -960,7 +962,7 @@ void setupBuiltins() {
BoxedHeapClass* ellipsis_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(Box), false, "ellipsis");
Box* Ellipsis = new (ellipsis_cls) Box();
Ellipsis = new (ellipsis_cls) Box();
assert(Ellipsis->cls);
gc::registerPermanentRoot(Ellipsis);
......@@ -1139,6 +1141,12 @@ void setupBuiltins() {
builtins_module->giveAttr("property", property_cls);
builtins_module->giveAttr("staticmethod", staticmethod_cls);
builtins_module->giveAttr("classmethod", classmethod_cls);
assert(memoryview_cls);
Py_TYPE(&PyMemoryView_Type) = &PyType_Type;
PyType_Ready(&PyMemoryView_Type);
builtins_module->giveAttr("memoryview", memoryview_cls);
builtins_module->giveAttr(
"eval", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)eval, UNKNOWN, 1, 0, false, false), "eval"));
......
......@@ -86,59 +86,6 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo
return new BoxedWrapperObject(self, inst);
}
extern "C" int PyObject_AsCharBuffer(PyObject* obj, const char** buffer, Py_ssize_t* buffer_len) noexcept {
Py_FatalError("unimplemented");
}
// copied from CPython's getargs.c:
extern "C" int PyBuffer_FillInfo(Py_buffer* view, PyObject* obj, void* buf, Py_ssize_t len, int readonly,
int flags) noexcept {
if (view == NULL)
return 0;
if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && (readonly == 1)) {
// Don't support PyErr_SetString yet:
assert(0);
// PyErr_SetString(PyExc_BufferError, "Object is not writable.");
// return -1;
}
view->obj = obj;
if (obj)
Py_INCREF(obj);
view->buf = buf;
view->len = len;
view->readonly = readonly;
view->itemsize = 1;
view->format = NULL;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = "B";
view->ndim = 1;
view->shape = NULL;
if ((flags & PyBUF_ND) == PyBUF_ND)
view->shape = &(view->len);
view->strides = NULL;
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)
view->strides = &(view->itemsize);
view->suboffsets = NULL;
view->internal = NULL;
return 0;
}
extern "C" void PyBuffer_Release(Py_buffer* view) noexcept {
if (!view->buf) {
assert(!view->obj);
return;
}
PyObject* obj = view->obj;
assert(obj);
assert(obj->cls == str_cls);
if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer)
Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view);
Py_XDECREF(obj);
view->obj = NULL;
}
extern "C" void _PyErr_BadInternalCall(const char* filename, int lineno) noexcept {
Py_FatalError("unimplemented");
}
......@@ -309,7 +256,8 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept
try {
return getattr(o, static_cast<BoxedString*>(attr_name)->s.c_str());
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
setCAPIException(e);
return NULL;
}
}
......@@ -340,7 +288,36 @@ extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) noexcept {
}
extern "C" PyObject* PyObject_RichCompare(PyObject* o1, PyObject* o2, int opid) noexcept {
int translated_op;
switch (opid) {
case Py_LT:
translated_op = AST_TYPE::Lt;
break;
case Py_LE:
translated_op = AST_TYPE::LtE;
break;
case Py_EQ:
translated_op = AST_TYPE::Eq;
break;
case Py_NE:
translated_op = AST_TYPE::NotEq;
break;
case Py_GT:
translated_op = AST_TYPE::Gt;
break;
case Py_GE:
translated_op = AST_TYPE::GtE;
break;
default:
Py_FatalError("unimplemented");
};
try {
return compare(o1, o2, translated_op);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" {
......@@ -896,280 +873,6 @@ extern "C" void PyMem_Free(void* ptr) noexcept {
gc_compat_free(ptr);
}
extern "C" int PyNumber_Check(PyObject* obj) noexcept {
assert(obj && obj->cls);
// Our check, since we don't currently fill in tp_as_number:
if (isSubclass(obj->cls, int_cls) || isSubclass(obj->cls, long_cls))
return true;
// The CPython check:
return obj->cls->tp_as_number && (obj->cls->tp_as_number->nb_int || obj->cls->tp_as_number->nb_float);
}
extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Add);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" PyObject* PyNumber_Subtract(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Sub);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Multiply(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mult);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Divide(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Div);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_FloorDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_TrueDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Remainder(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mod);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Divmod(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Power(PyObject*, PyObject*, PyObject* o3) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Positive(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Absolute(PyObject* o) noexcept {
try {
return abs_(o);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Invert(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Lshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::RShift);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::BitAnd);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
}
}
extern "C" PyObject* PyNumber_Xor(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Or(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceSubtract(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceMultiply(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceFloorDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceTrueDivide(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceRemainder(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlacePower(PyObject*, PyObject*, PyObject* o3) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceLshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceRshift(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceAnd(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceXor(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_InPlaceOr(PyObject*, PyObject*) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyNumber_Coerce(PyObject**, PyObject**) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyNumber_CoerceEx(PyObject**, PyObject**) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Int(PyObject* o) noexcept {
PyNumberMethods* m;
const char* buffer;
Py_ssize_t buffer_len;
if (o == NULL) {
PyErr_SetString(PyExc_SystemError, "null argument to internal routing");
return NULL;
}
if (PyInt_CheckExact(o)) {
Py_INCREF(o);
return o;
}
m = o->cls->tp_as_number;
if (m && m->nb_int) { /* This should include subclasses of int */
/* Classic classes always take this branch. */
PyObject* res = m->nb_int(o);
if (res && (!PyInt_Check(res) && !PyLong_Check(res))) {
PyErr_Format(PyExc_TypeError, "__int__ returned non-int (type %.200s)", res->cls->tp_name);
Py_DECREF(res);
return NULL;
}
return res;
}
if (PyInt_Check(o)) { /* A int subclass without nb_int */
BoxedInt* io = (BoxedInt*)o;
return PyInt_FromLong(io->n);
}
Py_FatalError("unimplemented __trunc__ and string -> int conversion");
// the remainder of PyNumber_Int deals with __trunc__ usage, and converting from unicode/string to int
#if 0
PyObject* trunc_func = getattr(o, "__trunc__");
if (trunc_func) {
PyObject *truncated = PyEval_CallObject(trunc_func, NULL);
Py_DECREF(trunc_func);
/* __trunc__ is specified to return an Integral type, but
int() needs to return an int. */
return _PyNumber_ConvertIntegralToInt(
truncated,
"__trunc__ returned non-Integral (type %.200s)");
}
PyErr_Clear(); /* It's not an error if o.__trunc__ doesn't exist. */
if (PyString_Check(o))
return int_from_string(PyString_AS_STRING(o),
PyString_GET_SIZE(o));
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(o))
return PyInt_FromUnicode(PyUnicode_AS_UNICODE(o),
PyUnicode_GET_SIZE(o),
10);
#endif
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
return int_from_string((char*)buffer, buffer_len);
return type_error("int() argument must be a string or a "
"number, not '%.200s'", o);
#endif
}
extern "C" PyObject* PyNumber_Long(PyObject* o) noexcept {
// This method should do quite a bit more, including checking tp_as_number->nb_long or calling __trunc__
if (o->cls == long_cls)
return o;
if (o->cls == float_cls)
return PyLong_FromDouble(PyFloat_AsDouble(o));
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Float(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_Index(PyObject* o) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) noexcept {
Py_FatalError("unimplemented");
}
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) noexcept {
RELEASE_ASSERT(o->cls != long_cls, "unhandled");
RELEASE_ASSERT(isSubclass(o->cls, int_cls), "??");
int64_t n = static_cast<BoxedInt*>(o)->n;
static_assert(sizeof(n) == sizeof(Py_ssize_t), "");
return n;
}
extern "C" int PyBuffer_IsContiguous(Py_buffer* view, char fort) noexcept {
Py_FatalError("unimplemented");
}
extern "C" int PyOS_snprintf(char* str, size_t size, const char* format, ...) noexcept {
int rc;
va_list va;
......
......@@ -294,7 +294,14 @@ extern "C" PyObject* PyImport_ImportModule(const char* name) noexcept {
if (strcmp("__builtin__", name) == 0)
return builtins_module;
Py_FatalError("unimplemented");
try {
// TODO: check if this has the same behaviour as the cpython implementation
std::string str = name;
return import(0, None, &str);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" Box* import(int level, Box* from_imports, const std::string* module_name) {
......
......@@ -33,6 +33,10 @@
namespace pyston {
extern "C" unsigned long PyInt_AsUnsignedLongMask(PyObject* op) noexcept {
if (op && PyInt_Check(op))
return PyInt_AS_LONG((PyIntObject*)op);
if (op && PyLong_Check(op))
return PyLong_AsUnsignedLongMask(op);
Py_FatalError("unimplemented");
}
......
......@@ -78,7 +78,12 @@ extern "C" int _PyLong_AsInt(PyObject* obj) noexcept {
return (int)result;
}
extern "C" unsigned long PyLong_AsUnsignedLongMask(PyObject* op) noexcept {
extern "C" unsigned long PyLong_AsUnsignedLongMask(PyObject* vv) noexcept {
if (PyLong_Check(vv)) {
BoxedLong* l = static_cast<BoxedLong*>(vv);
return mpz_get_ui(l->n);
}
Py_FatalError("unimplemented");
}
......@@ -136,10 +141,29 @@ extern "C" unsigned long PyLong_AsUnsignedLong(PyObject* vv) noexcept {
}
extern "C" long PyLong_AsLong(PyObject* vv) noexcept {
int overflow;
long result = PyLong_AsLongAndOverflow(vv, &overflow);
if (overflow) {
/* XXX: could be cute and give a different
message for overflow == -1 */
PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C long");
}
return result;
}
extern "C" Py_ssize_t PyLong_AsSsize_t(PyObject* vv) noexcept {
RELEASE_ASSERT(PyLong_Check(vv), "");
if (PyLong_Check(vv)) {
BoxedLong* l = static_cast<BoxedLong*>(vv);
RELEASE_ASSERT(mpz_fits_slong_p(l->n), "");
if (mpz_fits_slong_p(l->n)) {
return mpz_get_si(l->n);
} else {
PyErr_SetString(PyExc_OverflowError, "long int too large to convert to int");
return -1;
}
}
Py_FatalError("unimplemented");
}
extern "C" long PyLong_AsLongAndOverflow(Box* vv, int* overflow) noexcept {
......@@ -155,7 +179,28 @@ extern "C" long PyLong_AsLongAndOverflow(Box* vv, int* overflow) noexcept {
if (PyInt_Check(vv))
return PyInt_AsLong(vv);
if (PyLong_Check(vv)) {
if (!PyLong_Check(vv)) {
PyNumberMethods* nb;
nb = vv->cls->tp_as_number;
if (nb == NULL || nb->nb_int == NULL) {
PyErr_SetString(PyExc_TypeError, "an integer is required");
return -1;
}
vv = (*nb->nb_int)(vv);
if (vv == NULL)
return -1;
if (PyInt_Check(vv))
return PyInt_AsLong(vv);
if (!PyLong_Check(vv)) {
PyErr_SetString(PyExc_TypeError, "nb_int should return int object");
return -1;
}
// fallthrough: this has to be a long
}
BoxedLong* l = static_cast<BoxedLong*>(vv);
if (mpz_fits_slong_p(l->n)) {
return mpz_get_si(l->n);
......@@ -163,10 +208,6 @@ extern "C" long PyLong_AsLongAndOverflow(Box* vv, int* overflow) noexcept {
*overflow = mpz_sgn(l->n);
return -1;
}
}
// TODO CPython tries to go through tp_as_number
Py_FatalError("unsupported case");
}
extern "C" double PyLong_AsDouble(PyObject* vv) noexcept {
......@@ -288,11 +329,6 @@ extern "C" PyObject* _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
if (n == 0)
return PyLong_FromLong(0);
if (is_signed) {
Py_FatalError("unimplemented");
return 0;
}
if (!little_endian) {
// TODO: check if the behaviour of mpz_import is right when big endian is specified.
Py_FatalError("unimplemented");
......@@ -302,6 +338,17 @@ extern "C" PyObject* _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
BoxedLong* rtn = new BoxedLong();
mpz_init(rtn->n);
mpz_import(rtn->n, 1, 1, n, little_endian ? -1 : 1, 0, &bytes[0]);
RELEASE_ASSERT(little_endian, "");
if (is_signed && bytes[n - 1] >= 0x80) { // todo add big endian support
mpz_t t;
mpz_init(t);
mpz_setbit(t, n * 8);
mpz_sub(rtn->n, rtn->n, t);
mpz_clear(t);
}
return rtn;
}
......@@ -367,6 +414,8 @@ BoxedLong* _longNew(Box* val, Box* _base) {
const std::string& s = static_cast<BoxedString*>(val)->s;
int r = mpz_init_set_str(rtn->n, s.c_str(), 10);
RELEASE_ASSERT(r == 0, "");
} else if (val->cls == float_cls) {
mpz_init_set_si(rtn->n, static_cast<BoxedFloat*>(val)->d);
} else {
static const std::string long_str("__long__");
Box* r = callattr(val, &long_str, CallattrFlags({.cls_only = true, .null_on_nonexistent = true }),
......
......@@ -307,6 +307,10 @@ extern "C" Box* strAdd(BoxedString* lhs, Box* _rhs) {
return new BoxedString(lhs->s + rhs->s);
}
extern "C" PyObject* PyString_InternFromString(const char* s) noexcept {
return new BoxedString(s);
}
/* Format codes
* F_LJUST '-'
* F_SIGN '+'
......@@ -1523,6 +1527,16 @@ Box* strJoin(BoxedString* self, Box* rhs) {
return boxString(std::move(output_str));
}
extern "C" PyObject* _PyString_Join(PyObject* sep, PyObject* x) noexcept {
try {
RELEASE_ASSERT(sep->cls == str_cls, "");
return strJoin((BoxedString*)sep, x);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
Box* strReplace(Box* _self, Box* _old, Box* _new, Box** _args) {
if (_self->cls != str_cls)
raiseExcHelper(TypeError, "descriptor 'replace' requires a 'str' object but received a '%s'",
......@@ -2193,6 +2207,14 @@ static Py_ssize_t string_buffer_getsegcount(PyObject* o, Py_ssize_t* lenp) noexc
return 1;
}
static Py_ssize_t string_buffer_getcharbuf(PyStringObject* self, Py_ssize_t index, const char** ptr) {
if (index != 0) {
PyErr_SetString(PyExc_SystemError, "accessing non-existent string segment");
return -1;
}
return string_buffer_getreadbuf((PyObject*)self, index, (const void**)ptr);
}
static int string_buffer_getbuffer(BoxedString* self, Py_buffer* view, int flags) noexcept {
assert(self->cls == str_cls);
return PyBuffer_FillInfo(view, (PyObject*)self, &self->s[0], self->s.size(), 1, flags);
......@@ -2202,7 +2224,7 @@ static PyBufferProcs string_as_buffer = {
(readbufferproc)string_buffer_getreadbuf, // comments are the only way I've found of
(writebufferproc)NULL, // forcing clang-format to break these onto multiple lines
(segcountproc)string_buffer_getsegcount, //
(charbufferproc)NULL, //
(charbufferproc)string_buffer_getcharbuf, //
(getbufferproc)string_buffer_getbuffer, //
(releasebufferproc)NULL,
};
......
......@@ -69,6 +69,7 @@ extern "C" void _PyUnicode_Init();
extern "C" void initunicodedata();
extern "C" void init_weakref();
extern "C" void initcStringIO();
extern "C" void init_io();
namespace pyston {
......@@ -1542,6 +1543,7 @@ void setupRuntime() {
initunicodedata();
init_weakref();
initcStringIO();
init_io();
// some additional setup to ensure weakrefs participate in our GC
BoxedClass* weakref_ref_cls = &_PyWeakref_RefType;
......
......@@ -84,6 +84,7 @@ extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float
*builtin_function_or_method_cls;
}
#define unicode_cls (&PyUnicode_Type)
#define memoryview_cls (&PyMemoryView_Type)
extern "C" {
extern Box* None, *NotImplemented, *True, *False;
......
# allow-warning: import level 0 will be treated as -1
import gzip
import io
text = "Hello World!"
# generate zip in memory
outdata = io.BytesIO()
timestamp = 1
f = gzip.GzipFile(None, "wb", 9, outdata, timestamp)
print f.write(text)
f.close()
output = outdata.getvalue()
print output.encode("base64")
# decode zip from memory
f = gzip.GzipFile(None, "rb", 9, io.BytesIO(output))
print f.read()
f.close()
# allow-warning: import level 0 will be treated as -1
import io
filename = "io_test_.txt"
f = io.open(filename, "w")
print type(f)
print f.isatty()
print f.write(unicode("Hello World"))
print f.tell()
f.close()
f = io.StringIO()
print type(f)
f.write(unicode('First line.\n'))
f.write(unicode('Second line.\n'))
print f.getvalue()
print f.isatty()
print f.tell()
f.close()
f = io.open(filename)
print type(f)
print f.read()
f.close()
......@@ -45,6 +45,9 @@ except ValueError, e:
print long("100", 16)
print long("100", 10)
print long("100", 26)
print long(-1.1)
print long(1.9)
print long(-1.9)
print type(hash(1L))
print hash(1L) == hash(2L)
......
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