File: structmember.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (142 lines) | stat: -rw-r--r-- 6,243 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.structmemberdefs import *
from pypy.module.cpyext.api import ADDR, PyObjectP, cpython_api, CONST_STRING
from pypy.module.cpyext.longobject import PyLong_AsLong, PyLong_AsUnsignedLong
from pypy.module.cpyext.pyerrors import PyErr_Occurred
from pypy.module.cpyext.pyobject import PyObject, decref, from_ref, make_ref
from pypy.module.cpyext.unicodeobject import PyUnicode_FromString
from pypy.module.cpyext.floatobject import PyFloat_AsDouble
from pypy.module.cpyext.longobject import (
    PyLong_AsLongLong, PyLong_AsUnsignedLongLong, PyLong_AsSsize_t)
from pypy.module.cpyext.typeobjectdefs import PyMemberDef
from rpython.rlib.unroll import unrolling_iterable

def convert_bool(space, w_obj):
    if space.is_w(w_obj, space.w_False):
        return False
    if space.is_w(w_obj, space.w_True):
        return True
    raise oefmt(space.w_TypeError, "attribute value type must be bool")

integer_converters = unrolling_iterable([                     # range checking
    (T_SHORT,  rffi.SHORT,  PyLong_AsLong,                    True),
    (T_INT,    rffi.INT,    PyLong_AsLong,                    True),
    (T_LONG,   rffi.LONG,   PyLong_AsLong,                    False),
    (T_USHORT, rffi.USHORT, PyLong_AsUnsignedLong,            True),
    (T_UINT,   rffi.UINT,   PyLong_AsUnsignedLong,            True),
    (T_ULONG,  rffi.ULONG,  PyLong_AsUnsignedLong,            False),
    (T_BYTE,   rffi.SIGNEDCHAR, PyLong_AsLong,                True),
    (T_UBYTE,  rffi.UCHAR,  PyLong_AsUnsignedLong,            True),
    (T_BOOL,   rffi.UCHAR,  convert_bool,                     False),
    (T_FLOAT,  rffi.FLOAT,  PyFloat_AsDouble,                 False),
    (T_DOUBLE, rffi.DOUBLE, PyFloat_AsDouble,                 False),
    (T_LONGLONG,  rffi.LONGLONG,  PyLong_AsLongLong,          False),
    (T_ULONGLONG, rffi.ULONGLONG, PyLong_AsUnsignedLongLong,  False),
    (T_PYSSIZET, rffi.SSIZE_T, PyLong_AsSsize_t,              False),
    ])

_HEADER = 'pypy_structmember_decl.h'


@cpython_api([CONST_STRING, lltype.Ptr(PyMemberDef)], PyObject, header=_HEADER)
def PyMember_GetOne(space, obj, w_member):
    addr = rffi.cast(ADDR, obj)
    addr += w_member.c_offset

    member_type = rffi.cast(lltype.Signed, w_member.c_type)
    for converter in integer_converters:
        typ, lltyp, _, _ = converter
        if typ == member_type:
            result = rffi.cast(rffi.CArrayPtr(lltyp), addr)
            if lltyp is rffi.FLOAT:
                w_result = space.newfloat(lltype.cast_primitive(lltype.Float,
                                                            result[0]))
            elif typ == T_BOOL:
                x = rffi.cast(lltype.Signed, result[0])
                w_result = space.newbool(x != 0)
            elif typ == T_DOUBLE:
                w_result = space.newfloat(result[0])
            else:
                w_result = space.newint(result[0])
            return w_result

    if member_type == T_STRING:
        result = rffi.cast(rffi.CCHARPP, addr)
        if result[0]:
            w_result = PyUnicode_FromString(space, result[0])
        else:
            w_result = space.w_None
    elif member_type == T_STRING_INPLACE:
        result = rffi.cast(rffi.CCHARP, addr)
        w_result = PyUnicode_FromString(space, result)
    elif member_type == T_CHAR:
        result = rffi.cast(rffi.CCHARP, addr)
        w_result = space.newtext(result[0])
    elif member_type == T_OBJECT:
        obj_ptr = rffi.cast(PyObjectP, addr)
        if obj_ptr[0]:
            w_result = from_ref(space, obj_ptr[0])
        else:
            w_result = space.w_None
    elif member_type == T_OBJECT_EX:
        obj_ptr = rffi.cast(PyObjectP, addr)
        if obj_ptr[0]:
            w_result = from_ref(space, obj_ptr[0])
        else:
            w_name = space.newtext(rffi.charp2str(w_member.c_name))
            raise OperationError(space.w_AttributeError, w_name)
    else:
        raise oefmt(space.w_SystemError, "bad memberdescr type")
    return w_result


@cpython_api([rffi.CCHARP, lltype.Ptr(PyMemberDef), PyObject], rffi.INT_real,
             error=-1, header=_HEADER)
def PyMember_SetOne(space, obj, w_member, w_value):
    addr = rffi.cast(ADDR, obj)
    addr += w_member.c_offset
    member_type = rffi.cast(lltype.Signed, w_member.c_type)
    flags = rffi.cast(lltype.Signed, w_member.c_flags)

    if flags & READONLY:
        raise oefmt(space.w_AttributeError, "readonly attribute")
    elif member_type in [T_STRING, T_STRING_INPLACE]:
        raise oefmt(space.w_TypeError, "readonly attribute")
    elif w_value is None:
        if member_type == T_OBJECT_EX:
            if not rffi.cast(PyObjectP, addr)[0]:
                w_name = space.newtext(rffi.charp2str(w_member.c_name))
                raise OperationError(space.w_AttributeError, w_name)
        elif member_type != T_OBJECT:
            raise oefmt(space.w_TypeError,
                        "can't delete numeric/char attribute")

    for converter in integer_converters:
        typ, lltyp, getter, range_checking = converter
        if typ == member_type:
            value = getter(space, w_value)
            array = rffi.cast(rffi.CArrayPtr(lltyp), addr)
            casted = rffi.cast(lltyp, value)
            if range_checking:
                if rffi.cast(lltype.typeOf(value), casted) != value:
                    space.warn(space.newtext("structmember: truncation of value"),
                               space.w_RuntimeWarning)
            array[0] = casted
            return 0

    if member_type == T_CHAR:
        str_value = space.text_w(w_value)
        if len(str_value) != 1:
            raise oefmt(space.w_TypeError, "string of length 1 expected")
        array = rffi.cast(rffi.CCHARP, addr)
        array[0] = str_value[0]
    elif member_type in [T_OBJECT, T_OBJECT_EX]:
        array = rffi.cast(PyObjectP, addr)
        if array[0]:
            decref(space, array[0])
        array[0] = make_ref(space, w_value)
    else:
        raise oefmt(space.w_SystemError, "bad memberdescr type")
    return 0