~ubuntu-branches/ubuntu/precise/gst0.10-python/precise

« back to all changes in this revision

Viewing changes to codegen/reversewrapper.py

  • Committer: Bazaar Package Importer
  • Author(s): Loic Minier
  • Date: 2006-06-25 19:37:45 UTC
  • Revision ID: james.westby@ubuntu.com-20060625193745-9yeg0wq56r24n57x
Tags: upstream-0.10.4
ImportĀ upstreamĀ versionĀ 0.10.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
### -*- python -*-
 
2
### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
 
3
### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
 
4
import argtypes
 
5
 
 
6
def join_ctype_name(ctype, name):
 
7
    '''Joins a C type and a variable name into a single string'''
 
8
    if ctype[-1] != '*':
 
9
        return " ".join((ctype, name))
 
10
    else:
 
11
        return "".join((ctype, name))
 
12
 
 
13
 
 
14
class CodeSink(object):
 
15
    def __init__(self):
 
16
        self.indent_level = 0 # current indent level
 
17
        self.indent_stack = [] # previous indent levels
 
18
 
 
19
    def _format_code(self, code):
 
20
        assert isinstance(code, str)
 
21
        l = []
 
22
        for line in code.split('\n'):
 
23
            l.append(' '*self.indent_level + line)
 
24
        if l[-1]:
 
25
            l.append('')
 
26
        return '\n'.join(l)
 
27
    
 
28
    def writeln(self, line=''):
 
29
        raise NotImplementedError
 
30
    
 
31
    def indent(self, level=4):
 
32
        '''Add a certain ammount of indentation to all lines written
 
33
        from now on and until unindent() is called'''
 
34
        self.indent_stack.append(self.indent_level)
 
35
        self.indent_level += level
 
36
 
 
37
    def unindent(self):
 
38
        '''Revert indentation level to the value before last indent() call'''
 
39
        self.indent_level = self.indent_stack.pop()
 
40
 
 
41
 
 
42
class FileCodeSink(CodeSink):
 
43
    def __init__(self, fp):
 
44
        CodeSink.__init__(self)
 
45
        assert isinstance(fp, file)
 
46
        self.fp = fp
 
47
 
 
48
    def writeln(self, line=''):
 
49
        self.fp.write(self._format_code(line))
 
50
 
 
51
class MemoryCodeSink(CodeSink):
 
52
    def __init__(self):
 
53
        CodeSink.__init__(self)
 
54
        self.lines = []
 
55
 
 
56
    def writeln(self, line=''):
 
57
        self.lines.append(self._format_code(line))
 
58
 
 
59
    def flush_to(self, sink):
 
60
        assert isinstance(sink, CodeSink)
 
61
        for line in self.lines:
 
62
            sink.writeln(line.rstrip())
 
63
        self.lines = []
 
64
 
 
65
    def flush(self):
 
66
        l = []
 
67
        for line in self.lines:
 
68
            l.append(self._format_code(line))
 
69
        self.lines = []
 
70
        return "".join(l)
 
71
 
 
72
class ReverseWrapper(object):
 
73
    '''Object that generates a C->Python wrapper'''
 
74
    def __init__(self, cname, is_static=True):
 
75
        assert isinstance(cname, str)
 
76
 
 
77
        self.cname = cname
 
78
        ## function object we will call, or object whose method we will call 
 
79
        self.called_pyobj = None
 
80
        ## name of method of self.called_pyobj we will call
 
81
        self.method_name = None 
 
82
        self.is_static = is_static
 
83
 
 
84
        self.parameters = []
 
85
        self.declarations = MemoryCodeSink()
 
86
        self.body = MemoryCodeSink()
 
87
        self.cleanup_actions = []
 
88
        self.pyargv_items = []
 
89
        self.pyargv_optional_items = []
 
90
 
 
91
    def set_call_target(self, called_pyobj, method_name=None):
 
92
        assert called_pyobj is not None
 
93
        assert self.called_pyobj is None
 
94
        self.called_pyobj = called_pyobj
 
95
        self.method_name = method_name
 
96
 
 
97
    def set_return_type(self, return_type):
 
98
        assert isinstance(return_type, ReturnType)
 
99
        self.return_type = return_type
 
100
 
 
101
    def add_parameter(self, param):
 
102
        assert isinstance(param, Parameter)
 
103
        self.parameters.append(param)
 
104
 
 
105
    def add_declaration(self, decl_code):
 
106
        self.declarations.writeln(decl_code)
 
107
 
 
108
    def add_pyargv_item(self, variable, optional=False):
 
109
        if optional:
 
110
            self.pyargv_optional_items.append(variable)
 
111
        else:
 
112
            self.pyargv_items.append(variable)
 
113
 
 
114
    def write_code(self, code,
 
115
                 cleanup=None,
 
116
                 failure_expression=None,
 
117
                 failure_cleanup=None):
 
118
        '''Add a chunk of code with cleanup and error handling
 
119
 
 
120
        This method is to be used by TypeHandlers when generating code
 
121
 
 
122
        Keywork arguments:
 
123
        code -- code to add
 
124
        cleanup -- code to cleanup any dynamic resources created by @code
 
125
                   (except in case of failure) (default None)
 
126
        failure_expression -- C boolean expression to indicate
 
127
                              if anything failed (default None)
 
128
        failure_cleanup -- code to cleanup any dynamic resources
 
129
                           created by @code in case of failure (default None)
 
130
        '''
 
131
        if code is not None:
 
132
            self.body.writeln(code)
 
133
        if failure_expression is not None:
 
134
            self.body.writeln("if (%s) {" % failure_expression)
 
135
            self.body.indent()
 
136
            self.body.writeln("if (PyErr_Occurred())")
 
137
            self.body.indent()
 
138
            self.body.writeln("PyErr_Print();")
 
139
            self.body.unindent()
 
140
            if failure_cleanup is not None:
 
141
                self.body.writeln(failure_cleanup)
 
142
            for cleanup_action in self.cleanup_actions:
 
143
                self.body.writeln(cleanup_action)
 
144
            self.return_type.write_error_return()
 
145
            self.body.unindent()
 
146
            self.body.writeln("}")
 
147
        if cleanup is not None:
 
148
            self.cleanup_actions.insert(0, cleanup)
 
149
 
 
150
    def generate(self, sink):
 
151
        '''Generate the code into a CodeSink object'''
 
152
        assert isinstance(sink, CodeSink)
 
153
 
 
154
        self.add_declaration("PyGILState_STATE __py_state;")
 
155
        self.write_code(code="__py_state = pyg_gil_state_ensure();",
 
156
                        cleanup="pyg_gil_state_release(__py_state);")
 
157
 
 
158
        for param in self.parameters:
 
159
            param.convert_c2py()
 
160
 
 
161
        assert self.called_pyobj is not None,\
 
162
               "Parameters failed to provide a target function or method."
 
163
 
 
164
        if self.is_static:
 
165
            sink.writeln('static %s' % self.return_type.get_c_type())
 
166
        else:
 
167
            sink.writeln(self.return_type.get_c_type())
 
168
        c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
 
169
        sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
 
170
 
 
171
        self.return_type.write_decl()
 
172
        self.add_declaration("PyObject *py_retval;")
 
173
 
 
174
        ## Handle number of arguments
 
175
        if self.pyargv_items:
 
176
            self.add_declaration("PyObject *py_args;")
 
177
            py_args = "py_args"
 
178
            if self.pyargv_optional_items:
 
179
                self.add_declaration("int argc = %i;" % len(self.pyargv_items))
 
180
                argc = "argc"
 
181
                for arg in self.pyargv_optional_items:
 
182
                    self.body.writeln("if (%s)" % arg)
 
183
                    self.body.indent()
 
184
                    self.body.writeln("++argc;")
 
185
                    self.body.unindent()
 
186
            else:
 
187
                argc = str(len(self.pyargv_items))
 
188
        else:
 
189
            if self.pyargv_optional_items:
 
190
                self.add_declaration("PyObject *py_args;")
 
191
                py_args = "py_args"
 
192
                self.add_declaration("int argc = 0;")
 
193
                argc = "argc"
 
194
                for arg in self.pyargv_optional_items:
 
195
                    self.body.writeln("if (%s)" % arg)
 
196
                    self.body.indent()
 
197
                    self.body.writeln("++argc;")
 
198
                    self.body.unindent()
 
199
            else:
 
200
                py_args = "NULL"
 
201
                argc = None
 
202
 
 
203
        self.body.writeln()
 
204
        
 
205
        if py_args != "NULL":
 
206
            self.write_code("py_args = PyTuple_New(%s);" % argc,
 
207
                            cleanup="Py_DECREF(py_args);")
 
208
            pos = 0
 
209
            for arg in self.pyargv_items:
 
210
                try: # try to remove the Py_DECREF cleanup action, if we can
 
211
                    self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
 
212
                except ValueError: # otherwise we have to Py_INCREF..
 
213
                    self.body.writeln("Py_INCREF(%s);" % arg)
 
214
                self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
 
215
                pos += 1
 
216
            for arg in self.pyargv_optional_items:
 
217
                self.body.writeln("if (%s) {" % arg)
 
218
                self.body.indent()
 
219
                try: # try to remove the Py_DECREF cleanup action, if we can
 
220
                    self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
 
221
                except ValueError: # otherwise we have to Py_INCREF..
 
222
                    self.body.writeln("Py_INCREF(%s);" % arg)
 
223
                self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
 
224
                self.body.unindent()
 
225
                self.body.writeln("}")
 
226
                pos += 1
 
227
 
 
228
        self.body.writeln()
 
229
 
 
230
        # call it
 
231
        if self.method_name is None:
 
232
            self.write_code("py_retval = PyObject_Call(%s, %s);"
 
233
                            % (self.called_pyobj, py_args),
 
234
                            cleanup="Py_DECREF(py_retval);",
 
235
                            failure_expression="!py_retval")
 
236
        else:
 
237
            self.add_declaration("PyObject *py_method;")
 
238
            self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
 
239
                            % (self.called_pyobj, self.method_name),
 
240
                            cleanup="Py_DECREF(py_method);",
 
241
                            failure_expression="!py_method")
 
242
            self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
 
243
                            % (py_args,),
 
244
                            cleanup="Py_DECREF(py_retval);",
 
245
                            failure_expression="!py_retval")
 
246
        
 
247
        self.return_type.write_conversion()
 
248
 
 
249
        sink.indent()
 
250
        self.declarations.flush_to(sink)
 
251
        sink.writeln()
 
252
        self.body.flush_to(sink)
 
253
        sink.writeln()
 
254
        for cleanup_action in self.cleanup_actions:
 
255
            sink.writeln(cleanup_action)
 
256
        if self.return_type.get_c_type() != 'void':
 
257
            sink.writeln()
 
258
            sink.writeln("return retval;")
 
259
        sink.unindent()
 
260
        sink.writeln("}")
 
261
 
 
262
class TypeHandler(object):
 
263
    def __init__(self, wrapper, **props):
 
264
        assert isinstance(wrapper, ReverseWrapper)
 
265
        self.wrapper = wrapper
 
266
        self.props = props
 
267
 
 
268
class ReturnType(TypeHandler):
 
269
 
 
270
    def get_c_type(self):
 
271
        raise NotImplementedError
 
272
 
 
273
    def write_decl(self):
 
274
        raise NotImplementedError
 
275
 
 
276
    def write_error_return(self):
 
277
        '''Write "return <value>" code in case of error'''
 
278
        raise NotImplementedError
 
279
 
 
280
    def write_conversion(self):
 
281
        '''Writes code to convert Python return value in 'py_retval'
 
282
        into C 'retval'.  Returns a string with C boolean expression
 
283
        that determines if anything went wrong. '''
 
284
        raise NotImplementedError
 
285
 
 
286
class Parameter(TypeHandler):
 
287
 
 
288
    def __init__(self, wrapper, name, **props):
 
289
        TypeHandler.__init__(self, wrapper, **props)
 
290
        self.name = name
 
291
 
 
292
    def get_c_type(self):
 
293
        raise NotImplementedError
 
294
 
 
295
    def convert_c2py(self):
 
296
        '''Write some code before calling the Python method.'''
 
297
        pass
 
298
 
 
299
    def format_for_c_proto(self):
 
300
        return join_ctype_name(self.get_c_type(), self.name)
 
301
 
 
302
 
 
303
###---
 
304
class StringParam(Parameter):
 
305
 
 
306
    def get_c_type(self):
 
307
        return self.props.get('c_type', 'char *').replace('const-', 'const ')
 
308
 
 
309
    def convert_c2py(self):
 
310
        if self.props.get('optional', False):
 
311
            self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
 
312
            self.wrapper.write_code(code=("if (%s)\n"
 
313
                                          "    py_%s = PyString_FromString(%s);\n"
 
314
                                          % (self.name, self.name, self.name)),
 
315
                                    cleanup=("Py_XDECREF(py_%s);" % self.name))
 
316
            self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
 
317
        else:
 
318
            self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
319
            self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
 
320
                                          (self.name, self.name)),
 
321
                                    cleanup=("Py_DECREF(py_%s);" % self.name),
 
322
                                    failure_expression=("!py_%s" % self.name))
 
323
            self.wrapper.add_pyargv_item("py_%s" % self.name)
 
324
 
 
325
for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
 
326
              'gchar-const*', 'string', 'static_string'):
 
327
    argtypes.matcher.register_reverse(ctype, StringParam)
 
328
 
 
329
 
 
330
class StringReturn(ReturnType):
 
331
 
 
332
    def get_c_type(self):
 
333
        return "char *"
 
334
 
 
335
    def write_decl(self):
 
336
        self.wrapper.add_declaration("char *retval;")
 
337
 
 
338
    def write_error_return(self):
 
339
        self.wrapper.write_code("return NULL;")
 
340
 
 
341
    def write_conversion(self):
 
342
        self.wrapper.write_code(
 
343
            code=None,
 
344
            failure_expression="!PyString_Check(py_retval)",
 
345
            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");')
 
346
        self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));")
 
347
 
 
348
for ctype in ('char*', 'gchar*'):
 
349
    argtypes.matcher.register_reverse(ctype, StringReturn)
 
350
 
 
351
 
 
352
 
 
353
class VoidReturn(ReturnType):
 
354
 
 
355
    def get_c_type(self):
 
356
        return "void"
 
357
 
 
358
    def write_decl(self):
 
359
        pass
 
360
 
 
361
    def write_error_return(self):
 
362
        self.wrapper.write_code("return;")
 
363
 
 
364
    def write_conversion(self):
 
365
        self.wrapper.write_code(
 
366
            code=None,
 
367
            failure_expression="py_retval != Py_None",
 
368
            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
 
369
 
 
370
argtypes.matcher.register_reverse_ret('void', VoidReturn)
 
371
argtypes.matcher.register_reverse_ret('none', VoidReturn)
 
372
 
 
373
class GObjectParam(Parameter):
 
374
 
 
375
    def get_c_type(self):
 
376
        return self.props.get('c_type', 'GObject *')
 
377
 
 
378
    def convert_c2py(self):
 
379
        self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
 
380
        self.wrapper.write_code(code=("if (%s)\n"
 
381
                                      "    py_%s = pygobject_new((GObject *) %s);\n"
 
382
                                      "else {\n"
 
383
                                      "    Py_INCREF(Py_None);\n"
 
384
                                      "    py_%s = Py_None;\n"
 
385
                                      "}"
 
386
                                      % (self.name, self.name, self.name, self.name)),
 
387
                                cleanup=("Py_DECREF(py_%s);" % self.name))
 
388
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
389
 
 
390
argtypes.matcher.register_reverse('GObject*', GObjectParam)
 
391
 
 
392
class GObjectReturn(ReturnType):
 
393
 
 
394
    def get_c_type(self):
 
395
        return self.props.get('c_type', 'GObject *')
 
396
 
 
397
    def write_decl(self):
 
398
        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
 
399
 
 
400
    def write_error_return(self):
 
401
        self.wrapper.write_code("return NULL;")
 
402
 
 
403
    def write_conversion(self):
 
404
        self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
 
405
                                % self.get_c_type())
 
406
        self.wrapper.write_code("g_object_ref((GObject *) retval);")
 
407
 
 
408
argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
 
409
 
 
410
 
 
411
 
 
412
class IntParam(Parameter):
 
413
 
 
414
    def get_c_type(self):
 
415
        return self.props.get('c_type', 'int')
 
416
 
 
417
    def convert_c2py(self):
 
418
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
419
        self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
 
420
                                      (self.name, self.name)),
 
421
                                cleanup=("Py_DECREF(py_%s);" % self.name))
 
422
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
423
 
 
424
class IntReturn(ReturnType):
 
425
    def get_c_type(self):
 
426
        return self.props.get('c_type', 'int')
 
427
    def write_decl(self):
 
428
        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
 
429
    def write_error_return(self):
 
430
        self.wrapper.write_code("return -G_MAXINT;")
 
431
    def write_conversion(self):
 
432
        self.wrapper.write_code(
 
433
            code=None,
 
434
            failure_expression="!PyInt_Check(py_retval)",
 
435
            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an int");')
 
436
        self.wrapper.write_code("retval = PyInt_AsLong(py_retval);")
 
437
 
 
438
for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
 
439
                'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
 
440
                'gint16', 'gint32', 'GTime'):
 
441
    argtypes.matcher.register_reverse(argtype, IntParam)
 
442
    argtypes.matcher.register_reverse_ret(argtype, IntReturn)
 
443
 
 
444
 
 
445
class GEnumReturn(IntReturn):
 
446
    def write_conversion(self):
 
447
        self.wrapper.write_code(
 
448
            code=None,
 
449
            failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
 
450
                                self.props['typecode']))
 
451
 
 
452
argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
 
453
 
 
454
class GEnumParam(IntParam):
 
455
    def convert_c2py(self):
 
456
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
457
        self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
 
458
                                      (self.name, self.props['typecode'], self.name)),
 
459
                                cleanup=("Py_DECREF(py_%s);" % self.name),
 
460
                                failure_expression=("!py_%s" % self.name))
 
461
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
462
 
 
463
argtypes.matcher.register_reverse("GEnum", GEnumParam)
 
464
 
 
465
class GFlagsReturn(IntReturn):
 
466
    def write_conversion(self):
 
467
        self.wrapper.write_code(
 
468
            code=None,
 
469
            failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
 
470
                                self.props['typecode']))
 
471
 
 
472
argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
 
473
 
 
474
class GFlagsParam(IntParam):
 
475
    def convert_c2py(self):
 
476
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
477
        self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
 
478
                                      (self.name, self.props['typecode'], self.name)),
 
479
                                cleanup=("Py_DECREF(py_%s);" % self.name),
 
480
                                failure_expression=("!py_%s" % self.name))
 
481
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
482
 
 
483
argtypes.matcher.register_reverse("GFlags", GFlagsParam)
 
484
 
 
485
 
 
486
class GtkTreePathParam(IntParam):
 
487
    def convert_c2py(self):
 
488
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
489
        self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
 
490
                                      (self.name, self.name)),
 
491
                                cleanup=("Py_DECREF(py_%s);" % self.name),
 
492
                                failure_expression=("!py_%s" % self.name))
 
493
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
494
 
 
495
argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
 
496
 
 
497
 
 
498
class BooleanReturn(ReturnType):
 
499
    def get_c_type(self):
 
500
        return "gboolean"
 
501
    def write_decl(self):
 
502
        self.wrapper.add_declaration("gboolean retval;")
 
503
    def write_error_return(self):
 
504
        self.wrapper.write_code("return FALSE;")
 
505
    def write_conversion(self):
 
506
        self.wrapper.write_code("retval = PyObject_IsTrue(py_retval)? TRUE : FALSE;")
 
507
argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
 
508
 
 
509
class BooleanParam(Parameter):
 
510
    def get_c_type(self):
 
511
        return "gboolean"
 
512
    def convert_c2py(self):
 
513
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
514
        self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
 
515
                                % (self.name, self.name))
 
516
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
517
 
 
518
argtypes.matcher.register_reverse("gboolean", BooleanParam)
 
519
 
 
520
 
 
521
class DoubleParam(Parameter):
 
522
    def get_c_type(self):
 
523
        return self.props.get('c_type', 'gdouble')
 
524
    def convert_c2py(self):
 
525
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
526
        self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
 
527
                                      (self.name, self.name)),
 
528
                                cleanup=("Py_DECREF(py_%s);" % self.name))
 
529
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
530
 
 
531
class DoubleReturn(ReturnType):
 
532
    def get_c_type(self):
 
533
        return self.props.get('c_type', 'gdouble')
 
534
    def write_decl(self):
 
535
        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
 
536
    def write_error_return(self):
 
537
        self.wrapper.write_code("return -G_MAXFLOAT;")
 
538
    def write_conversion(self):
 
539
        self.wrapper.write_code(
 
540
            code=None,
 
541
            failure_expression="!PyFloat_AsDouble(py_retval)",
 
542
            failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
 
543
        self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
 
544
 
 
545
for argtype in ('float', 'double', 'gfloat', 'gdouble'):
 
546
    argtypes.matcher.register_reverse(argtype, DoubleParam)
 
547
    argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
 
548
 
 
549
 
 
550
class GBoxedParam(Parameter):
 
551
    def get_c_type(self):
 
552
        return self.props.get('c_type').replace('const-', 'const ')
 
553
    def convert_c2py(self):
 
554
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
555
        ctype = self.get_c_type()
 
556
        if ctype.startswith('const '):
 
557
            ctype_no_const = ctype[len('const '):]
 
558
            self.wrapper.write_code(
 
559
                code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
 
560
                      (self.name, self.props['typecode'],
 
561
                       ctype_no_const, self.name)),
 
562
                cleanup=("Py_DECREF(py_%s);" % self.name))
 
563
        else:
 
564
            self.wrapper.write_code(
 
565
                code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
 
566
                      (self.name, self.props['typecode'], self.name)),
 
567
                cleanup=("Py_DECREF(py_%s);" % self.name))
 
568
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
569
 
 
570
argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
 
571
 
 
572
class GBoxedReturn(ReturnType):
 
573
    def get_c_type(self):
 
574
        return self.props.get('c_type')
 
575
    def write_decl(self):
 
576
        self.wrapper.add_declaration("%s retval;" % self.get_c_type())
 
577
    def write_error_return(self):
 
578
        self.wrapper.write_code("return retval;")
 
579
    def write_conversion(self):
 
580
        self.wrapper.write_code(
 
581
            failure_expression=("!pyg_boxed_check(py_retval, %s)" %
 
582
                                (self.props['typecode'],)),
 
583
            failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
 
584
                             % (self.props['typename'],)))
 
585
        self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
 
586
                                self.props['typename'])
 
587
 
 
588
argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
 
589
 
 
590
 
 
591
class GdkRectanglePtrParam(Parameter):
 
592
    def get_c_type(self):
 
593
        return self.props.get('c_type').replace('const-', 'const ')
 
594
    def convert_c2py(self):
 
595
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
596
        self.wrapper.write_code(
 
597
            code=('py_%(name)s = Py_BuildValue("(ffff)", %(name)s->x, %(name)s->y,\n'
 
598
                  '                            %(name)s->width, %(name)s->height);'
 
599
                  % dict(name=self.name)),
 
600
            cleanup=("Py_DECREF(py_%s);" % self.name))
 
601
        self.wrapper.add_pyargv_item("py_%s" % self.name)
 
602
 
 
603
argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
 
604
 
 
605
 
 
606
class PyGObjectMethodParam(Parameter):
 
607
    def __init__(self, wrapper, name, method_name, **props):
 
608
        Parameter.__init__(self, wrapper, name, **props)
 
609
        self.method_name = method_name
 
610
 
 
611
    def get_c_type(self):
 
612
        return self.props.get('c_type', 'GObject *')
 
613
 
 
614
    def convert_c2py(self):
 
615
        self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
 
616
        self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
 
617
                                      (self.name, self.name)),
 
618
                                cleanup=("Py_DECREF(py_%s);" % self.name),
 
619
                                failure_expression=("!py_%s" % self.name))
 
620
        self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
 
621
 
 
622
class CallbackInUserDataParam(Parameter):
 
623
    def __init__(self, wrapper, name, free_it, **props):
 
624
        Parameter.__init__(self, wrapper, name, **props)
 
625
        self.free_it = free_it
 
626
 
 
627
    def get_c_type(self):
 
628
        return "gpointer"
 
629
 
 
630
    def convert_c2py(self):
 
631
        self.wrapper.add_declaration("PyObject **_user_data;")
 
632
        cleanup = self.free_it and ("g_free(%s);" % self.name) or None
 
633
        self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
 
634
                                      % self.name),
 
635
                                cleanup=cleanup)
 
636
 
 
637
        self.wrapper.add_declaration("PyObject *py_func;")
 
638
        cleanup = self.free_it and "Py_DECREF(py_func);" or None
 
639
        self.wrapper.write_code(code="py_func = _user_data[0];",
 
640
                                cleanup=cleanup)
 
641
        self.wrapper.set_call_target("py_func")
 
642
 
 
643
        self.wrapper.add_declaration("PyObject *py_user_data;")
 
644
        cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
 
645
        self.wrapper.write_code(code="py_user_data = _user_data[1];",
 
646
                                cleanup=cleanup)
 
647
        self.wrapper.add_pyargv_item("py_user_data", optional=True)
 
648
 
 
649
def _test():
 
650
    import sys
 
651
 
 
652
    wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
 
653
    wrapper.set_return_type(StringReturn(wrapper))
 
654
    wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
 
655
    wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
 
656
    wrapper.add_parameter(GObjectParam(wrapper, "param3"))
 
657
    wrapper.generate(FileCodeSink(sys.stderr))
 
658
 
 
659
    wrapper = ReverseWrapper("this_a_callback_wrapper")
 
660
    wrapper.set_return_type(VoidReturn(wrapper))
 
661
    wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
 
662
    wrapper.add_parameter(GObjectParam(wrapper, "param2"))
 
663
    wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
 
664
    wrapper.generate(FileCodeSink(sys.stderr))
 
665
 
 
666
if __name__ == '__main__':
 
667
    _test()