Possible improvements of the rpython language¶
Improve the interpreter API¶
Rationalize the modules, and the names, of the different functions needed to implement a pypy module. A typical rpython file is likely to contain many import statements:
from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.gateway import ObjSpace, W_Root from pypy.interpreter.argument import Arguments from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w from pypy.interpreter.gateway import interp2app from pypy.interpreter.error import OperationError from rpython.rtyper.lltypesystem import rffi, lltype
A more direct declarative way to write Typedef:
class W_Socket(W_Root): _typedef_name_ = 'socket' _typedef_base_ = W_EventualBaseClass @interp2app_method("connect", ['self', ObjSpace, W_Root]) def connect_w(self, space, w_addr): ...
Support for metaclasses written in rpython. For a sample, see the skipped test pypy.objspace.std.test.TestTypeObject.test_metaclass_typedef
RPython language¶
Arithmetic with unsigned integer, and between integer of different signedness, when this is not ambiguous. At least, comparison and assignment with constants should be allowed.
Allocate variables on the stack, and pass their address (“by reference”) to llexternal functions. For a typical usage, see rpython.rlib.rsocket.RSocket.getsockopt_int.
Extensible type system for llexternal¶
llexternal allows the description of a C function, and conveys the same information about the arguments as a C header. But this is often not enough. For example, a parameter of type int* is converted to rffi.CArrayPtr(rffi.INT), but this information is not enough to use the function. The parameter could be an array of int, a reference to a single value, for input or output…
A “type system” could hold this additional information, and automatically generate some conversion code to ease the usage of the function from rpython. For example:
# double frexp(double x, int *exp);
frexp = llexternal("frexp", [rffi.DOUBLE, OutPtr(rffi.int)], rffi.DOUBLE)
OutPtr indicates that the parameter is output-only, which need not to be initialized, and which value is returned to the caller. In rpython the call becomes:
fraction, exponent = frexp(value)
Also, we could imagine that one item in the llexternal argument list corresponds to two parameters in C. Here, OutCharBufferN indicates that the caller will pass a rpython string; the framework will pass buffer and length to the function:
# ssize_t write(int fd, const void *buf, size_t count);
write = llexternal("write", [rffi.INT, CharBufferAndSize], rffi.SSIZE_T)
The rpython code that calls this function is very simple:
written = write(fd, data)
compared with the present:
count = len(data)
buf = rffi.get_nonmovingbuffer(data)
try:
written = rffi.cast(lltype.Signed, os_write(
rffi.cast(rffi.INT, fd),
buf, rffi.cast(rffi.SIZE_T, count)))
finally:
rffi.free_nonmovingbuffer(data, buf)
Typemaps are very useful for large APIs where the same conversions are needed in many places. XXX example