File: mkrffi.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (149 lines) | stat: -rw-r--r-- 5,460 bytes parent folder | download | duplicates (4)
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
143
144
145
146
147
148
149
import ctypes

import py

def primitive_pointer_repr(tp_s):
    return 'lltype.Ptr(lltype.FixedSizeArray(%s, 1))' % tp_s

# XXX any automatic stuff here?
SIMPLE_TYPE_MAPPING = {
    ctypes.c_ubyte     : 'rffi.UCHAR',
    ctypes.c_byte      : 'rffi.CHAR',
    ctypes.c_char      : 'rffi.CHAR',
    ctypes.c_int8      : 'rffi.CHAR',
    ctypes.c_ushort    : 'rffi.USHORT',
    ctypes.c_short     : 'rffi.SHORT',
    ctypes.c_uint16    : 'rffi.USHORT',
    ctypes.c_int16     : 'rffi.SHORT',
    ctypes.c_int       : 'rffi.INT',
    ctypes.c_uint      : 'rffi.UINT',
    ctypes.c_int32     : 'rffi.INT',
    ctypes.c_uint32    : 'rffi.UINT',
    ctypes.c_longlong  : 'rffi.LONGLONG',
    ctypes.c_ulonglong : 'rffi.ULONGLONG',
    ctypes.c_int64     : 'rffi.LONGLONG',
    ctypes.c_uint64    : 'rffi.ULONGLONG',
    ctypes.c_voidp     : 'rffi.VOIDP',
    None               : 'rffi.lltype.Void', # XXX make a type in rffi
    ctypes.c_char_p    : 'rffi.CCHARP',
    ctypes.c_double    : 'rffi.lltype.Float', # XXX make a type in rffi
}

class RffiSource(object):
    def __init__(self, structs=None, source=None, includes=[], libraries=[],
            include_dirs=[]):
        # set of ctypes structs
        if structs is None:
            self.structs = set()
        else:
            self.structs = structs
        if source is None:
            self.source = py.code.Source()
        else:
            self.source = source
        includes = includes and "includes=%s, " % repr(tuple(includes)) or ''
        libraries = libraries and "libraries=%s, " % repr(tuple(libraries)) or ''
        include_dirs = include_dirs and \
            "include_dirs=%s, " % repr(tuple(include_dirs)) or ''
        self.extra_args = includes+libraries+include_dirs
        self.seen = {}
        self.forward_refs = 0
        self.forward_refs_to_consider = {}

    def next_forward_reference(self):
        try:
            return "forward_ref%d" % self.forward_refs
        finally:
            self.forward_refs += 1

    def __str__(self):
        return str(self.source)

    def __add__(self, other):
        structs = self.structs.copy()
        structs.update(other.structs)
        source = py.code.Source(self.source, other.source)
        return RffiSource(structs, source)

    def __iadd__(self, other):
        self.structs.update(other.structs)
        self.source = py.code.Source(self.source, other.source)
        return self

    def proc_struct(self, tp):
        name = tp.__name__
        if tp not in self.structs:
            fields = ["('%s', %s), " % (name_, self.proc_tp(field_tp))
                      for name_, field_tp in tp._fields_]
            fields_repr = ''.join(fields)
            self.structs.add(tp)
            src = py.code.Source(
                "%s = lltype.Struct('%s', %s hints={'external':'C'})"%(
                    name, name, fields_repr))
            forward_ref = self.forward_refs_to_consider.get(tp, None)
            l = [self.source, src]
            if forward_ref:
                l.append(py.code.Source("\n%s.become(%s)\n" % (forward_ref, name)))
            self.source = py.code.Source(*l)
        return name

    def proc_forward_ref(self, tp):
        name = self.next_forward_reference()
        src = py.code.Source("""
        %s = lltype.ForwardReference()
        """ % (name,) )
        self.source = py.code.Source(self.source, src)
        self.forward_refs_to_consider[tp] = name
        return name
        
    def proc_tp(self, tp):
        try:
            return SIMPLE_TYPE_MAPPING[tp]
        except KeyError:
            pass
        if issubclass(tp, ctypes._Pointer):
            if issubclass(tp._type_, ctypes._SimpleCData):
                return "lltype.Ptr(lltype.Array(%s, hints={'nolength': True}))"\
                       % self.proc_tp(tp._type_)
            return "lltype.Ptr(%s)" % self.proc_tp(tp._type_)
        elif issubclass(tp, ctypes.Structure):
            if tp in self.seen:
                # recursive struct
                return self.proc_forward_ref(tp)
            self.seen[tp] = True
            return self.proc_struct(tp)
        elif issubclass(tp, ctypes.Array):
            return "lltype.Ptr(lltype.Array(%s, hints={'nolength': True}))" % \
                   self.proc_tp(tp._type_)
        raise NotImplementedError("Not implemented mapping for %s" % tp)

    def proc_func(self, func):
        name = func.__name__
        if not self.extra_args:
            extra_args = ""
        else:
            extra_args = ", " + self.extra_args
        src = py.code.Source("""
        %s = rffi.llexternal('%s', [%s], %s%s)
        """%(name, name, ", ".join([self.proc_tp(arg) for arg in func.argtypes]),
             self.proc_tp(func.restype), extra_args))
        self.source = py.code.Source(self.source, src)

    def proc_namespace(self, ns):
        exempt = set(id(value) for value in ctypes.__dict__.values())
        for key, value in ns.items():
            if id(value) in exempt: 
                continue
            if isinstance(value, ctypes._CFuncPtr):
                self.proc_func(value)
            #print value, value.__class__.__name__

    def compiled(self):
        # not caching!
        globs = {}
        src = py.code.Source("""
        from rpython.rtyper.lltypesystem import lltype
        from rpython.rtyper.lltypesystem import rffi
        """, self.source)
        exec src.compile() in globs
        return globs