root/trunk/infrastructure/pyd/op_wrap.d

Revision 100, 20.3 kB (checked in by KirkMcDonald, 1 year ago)

* Class wrapping API replaced.
* Inheritance "shim" classes now automatically generated.
* Requires DMD 1.005 or newer. Breaks GDC support for the moment.
* Docs not yet updated to reflect changes.
* Copyright notices updated to 2007.

Line 
1 /*
2 Copyright 2006, 2007 Kirk McDonald
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22 module pyd.op_wrap;
23
24 import python;
25
26 import pyd.class_wrap;
27 import pyd.dg_convert;
28 import pyd.func_wrap;
29 import pyd.exception;
30 import pyd.make_object;
31 import pyd.lib_abstract :
32     prettytypeof,
33     symbolnameof,
34     ParameterTypeTuple,
35     ReturnType
36 ;
37
38 //import meta.Nameof;
39 //import std.traits;
40
41 version(Python_2_5_Or_Later) {
42     alias Py_ssize_t index_t;
43     alias lenfunc lenfunc_t;
44     alias ssizeargfunc idxargfunc;
45     alias ssizessizeargfunc idxidxargfunc;
46     alias ssizeobjargproc idxobjargproc;
47     alias ssizessizeobjargproc idxidxobjargproc;
48 } else {
49     alias int index_t;
50     alias inquiry lenfunc_t;
51     alias intargfunc idxargfunc;
52     alias intintargfunc idxidxargfunc;
53     alias intobjargproc idxobjargproc;
54     alias intintobjargproc idxidxobjargproc;
55 }
56
57 template wrapped_class_as_number(T) {
58     static PyNumberMethods wrapped_class_as_number = {
59         opAdd_wrap!(T),       /*nb_add*/
60         opSub_wrap!(T),       /*nb_subtract*/
61         opMul_wrap!(T),       /*nb_multiply*/
62         opDiv_wrap!(T),       /*nb_divide*/
63         opMod_wrap!(T),       /*nb_remainder*/
64         null,                 /*nb_divmod*/
65         null,                 /*nb_power*/
66         opNeg_wrap!(T),       /*nb_negative*/
67         opPos_wrap!(T),       /*nb_positive*/
68         null,                 /*nb_absolute*/
69         null,                 /*nb_nonzero*/
70         opCom_wrap!(T),       /*nb_invert*/
71         opShl_wrap!(T),       /*nb_lshift*/
72         opShr_wrap!(T),       /*nb_rshift*/
73         opAnd_wrap!(T),       /*nb_and*/
74         opXor_wrap!(T),       /*nb_xor*/
75         opOr_wrap!(T),        /*nb_or*/
76         null,                 /*nb_coerce*/
77         null,                 /*nb_int*/
78         null,                 /*nb_long*/
79         null,                 /*nb_float*/
80         null,                 /*nb_oct*/
81         null,                 /*nb_hex*/
82         opAddAssign_wrap!(T), /*nb_inplace_add*/
83         opSubAssign_wrap!(T), /*nb_inplace_subtract*/
84         opMulAssign_wrap!(T), /*nb_inplace_multiply*/
85         opDivAssign_wrap!(T), /*nb_inplace_divide*/
86         opModAssign_wrap!(T), /*nb_inplace_remainder*/
87         null,                 /*nb_inplace_power*/
88         opShlAssign_wrap!(T), /*nb_inplace_lshift*/
89         opShrAssign_wrap!(T), /*nb_inplace_rshift*/
90         opAndAssign_wrap!(T), /*nb_inplace_and*/
91         opXorAssign_wrap!(T), /*nb_inplace_xor*/
92         opOrAssign_wrap!(T),  /*nb_inplace_or*/
93         null,                 /* nb_floor_divide */
94         null,                 /* nb_true_divide */
95         null,                 /* nb_inplace_floor_divide */
96         null,                 /* nb_inplace_true_divide */
97     };
98 }
99
100 template wrapped_class_as_sequence(T) {
101     static PySequenceMethods wrapped_class_as_sequence = {
102         length_wrap!(T),                 /*sq_length*/
103         opCat_wrap!(T),                  /*sq_concat*/
104         null,                            /*sq_repeat*/
105         opIndex_sequence_wrap!(T),       /*sq_item*/
106         opSlice_wrap!(T),                /*sq_slice*/
107         opIndexAssign_sequence_wrap!(T), /*sq_ass_item*/
108         opSliceAssign_wrap!(T),          /*sq_ass_slice*/
109         opIn_wrap!(T),                   /*sq_contains*/
110         opCatAssign_wrap!(T),            /*sq_inplace_concat*/
111         null,                            /*sq_inplace_repeat*/
112     };
113 }
114
115 template wrapped_class_as_mapping(T) {
116     static PyMappingMethods wrapped_class_as_mapping = {
117         null,                           /*mp_length*/
118         opIndex_mapping_wrap!(T),       /*mp_subscript*/
119         opIndexAssign_mapping_wrap!(T), /*mp_ass_subscript*/
120     };
121 }
122
123 //----------------//
124 // Implementation //
125 //----------------//
126 template opfunc_binary_wrap(T, alias opfn) {
127     alias wrapped_class_object!(T) wrap_object;
128     alias ParameterTypeTuple!(opfn) Info;
129     alias ReturnType!(opfn) Ret;
130     alias dg_wrapper!(T, typeof(&opfn)) get_dg;
131     extern(C)
132     PyObject* func(PyObject* self, PyObject* o) {
133         return exception_catcher(delegate PyObject*() {
134             auto dg = get_dg((cast(wrap_object*)self).d_obj, &opfn);
135             pragma(msg, prettytypeof!(typeof(dg)));
136             pragma(msg, symbolnameof!(opfn));
137             static if (is(Ret == void)) {
138                 dg(d_type!(Info[0])(o));
139                 Py_INCREF(Py_None);
140                 return Py_None;
141             } else {
142                 return _py(
143                     dg(
144                         d_type!(Info[0])(o)
145                     )
146                 );
147             }
148         });
149     }
150 }
151
152 template opfunc_unary_wrap(T, alias opfn) {
153     extern(C)
154     PyObject* func(PyObject* self) {
155         // method_wrap takes care of exception handling
156         return method_wrap!(T, opfn, typeof(&opfn)).func(self, null);
157     }
158 }
159
160 template opindex_sequence_pyfunc(T) {
161     alias wrapped_class_object!(T) wrap_object;
162    
163     extern(C)
164     PyObject* func(PyObject* self, index_t i) {
165         return exception_catcher(delegate PyObject*() {
166             return _py((cast(wrap_object*)self).d_obj.opIndex(i));
167         });
168     }
169 }
170
171 template opindexassign_sequence_pyfunc(T) {
172     alias wrapped_class_object!(T) wrap_object;
173     alias ParameterTypeTuple!(T.opIndexAssign) Info;
174     alias Info[0] AssignT;
175
176     extern(C)
177     int func(PyObject* self, index_t i, PyObject* o) {
178         return exception_catcher(delegate int() {
179             (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(AssignT)(o), i);
180             return 0;
181         });
182     }
183 }
184
185 template opindex_mapping_pyfunc(T) {
186     alias wrapped_class_object!(T) wrap_object;
187     alias ParameterTypeTuple!(T.opIndex) Info;
188     const uint ARGS = Info.length;
189
190     // Multiple arguments are converted into tuples, and thus become a standard
191     // wrapped member function call. A single argument is passed directly.
192     static if (ARGS == 1) {
193         alias Info[0] KeyT;
194         extern(C)
195         PyObject* func(PyObject* self, PyObject* key) {
196             return exception_catcher(delegate PyObject*() {
197                 return _py((cast(wrap_object*)self).d_obj.opIndex(d_type!(KeyT)(key)));
198             });
199         }
200     } else {
201         alias method_wrap!(T, T.opIndex, typeof(&T.opIndex)) opindex_methodT;
202         extern(C)
203         PyObject* func(PyObject* self, PyObject* key) {
204             int args;
205             if (!PyTuple_CheckExact(key)) {
206                 args = 1;
207             } else {
208                 args = PySequence_Length(key);
209             }
210             if (ARGS != args) {
211                 setWrongArgsError(args, ARGS, ARGS);
212                 return null;
213             }
214             return opindex_methodT.func(self, key);
215         }
216     }
217 }
218
219 template opindexassign_mapping_pyfunc(T) {
220     alias wrapped_class_object!(T) wrap_object;
221     alias ParameterTypeTuple!(T.opIndexAssign) Info;
222     const uint ARGS = Info.length;
223
224     static if (ARGS > 2) {
225         extern(C)
226         int func(PyObject* self, PyObject* key, PyObject* val) {
227             int args;
228             if (!PyTuple_CheckExact(key)) {
229                 args = 2;
230             } else {
231                 args = PySequence_Length(key) + 1;
232             }
233             if (ARGS != args) {
234                 setWrongArgsError(args, ARGS, ARGS);
235                 return -1;
236             }
237             // Build a new tuple with the value at the front.
238             PyObject* temp = PyTuple_New(ARGS);
239             if (temp is null) return -1;
240             scope(exit) Py_DECREF(temp);
241             PyTuple_SetItem(temp, 0, val);
242             for (int i=1; i<ARGS; ++i) {
243                 Py_INCREF(PyTuple_GetItem(key, i-1));
244                 PyTuple_SetItem(temp, i, PyTuple_GetItem(key, i-1));
245             }
246             method_wrap!(T, T.opIndexAssign, typeof(&T.opIndexAssign)).func(self, temp);
247             return 0;
248         }
249     } else {
250         alias Info[0] ValT;
251         alias Info[1] KeyT;
252
253         extern(C)
254         int func(PyObject* self, PyObject* key, PyObject* val) {
255             return exception_catcher(delegate int() {
256                 (cast(wrap_object*)self).d_obj.opIndexAssign(d_type!(ValT)(val), d_type!(KeyT)(key));
257                 return 0;
258             });
259         }
260     }
261 }
262
263 template opslice_pyfunc(T) {
264     alias wrapped_class_object!(T) wrap_object;
265
266     extern(C)
267     PyObject* func(PyObject* self, index_t i1, index_t i2) {
268         return exception_catcher(delegate PyObject*() {
269             return _py((cast(wrap_object*)self).d_obj.opSlice(i1, i2));
270         });
271     }
272 }
273
274 template opsliceassign_pyfunc(T) {
275     alias wrapped_class_object!(T) wrap_object;
276     alias ParameterTypeTuple!(T.opSliceAssign) Info;
277     alias Info[0] AssignT;
278
279     extern(C)
280     int func(PyObject* self, index_t i1, index_t i2, PyObject* o) {
281         return exception_catcher(delegate int() {
282             (cast(wrap_object*)self).d_obj.opSliceAssign(d_type!(AssignT)(o), i1, i2);
283             return 0;
284         });
285     }
286 }
287
288 template opin_wrap(T) {
289     alias wrapped_class_object!(T) wrap_object;
290     alias ParameterTypeTuple!(T.opIn_r) Info;
291     alias Info[0] OtherT;
292    
293     extern(C)
294     int func(PyObject* self, PyObject* val) {
295         return exception_catcher(delegate int() {
296             if ((cast(wrap_object*)self).d_obj.opIn_r(d_type!(OtherT)(val)))
297                 return 1;
298             else
299                 return 0;
300         });
301     }
302 }
303
304 template opcmp_wrap(T) {
305     alias wrapped_class_object!(T) wrap_object;
306     alias ParameterTypeTuple!(T.opCmp) Info;
307     alias Info[0] OtherT;
308     extern(C)
309     int func(PyObject* self, PyObject* other) {
310         return exception_catcher(delegate int() {
311             int result = (cast(wrap_object*)self).d_obj.opCmp(d_type!(OtherT)(other));
312             // The Python API reference specifies that tp_compare must return
313             // -1, 0, or 1. The D spec says opCmp may return any integer value,
314             // and just compares it with zero.
315             if (result < 0) return -1;
316             if (result == 0) return 0;
317             if (result > 0) return 1;
318         });
319     }
320 }
321
322 template length_pyfunc(T) {
323     alias wrapped_class_object!(T) wrap_object;
324
325     extern(C)
326     index_t func(PyObject* self) {
327         return exception_catcher(delegate int() {
328             return (cast(wrap_object*)self).d_obj.length();
329         });
330     }
331 }
332
333 //----------//
334 // Dispatch //
335 //----------//
336 template length_wrap(T) {
337     static if (
338         is(typeof(&T.length)) &&
339         is(typeof(T.length()) : index_t)
340     ) {
341         const lenfunc_t length_wrap = &length_pyfunc!(T).func;
342     } else {
343         const lenfunc_t length_wrap = null;
344     }
345 }
346
347 template opIndex_sequence_wrap(T) {
348     static if (
349         is(typeof(&T.opIndex)) &&
350         ParameterTypeTuple!(T.opIndex).length == 1 &&
351         is(ParameterTypeTuple!(T.opIndex)[0] : index_t)
352     ) {
353         const idxargfunc opIndex_sequence_wrap = &opindex_sequence_pyfunc!(T).func;
354     } else {
355         const idxargfunc opIndex_sequence_wrap = null;
356     }
357 }
358
359 template opIndexAssign_sequence_wrap(T) {
360     static if (
361         is(typeof(&T.opIndexAssign)) &&
362         ParameterTypeTuple!(T.opIndexAssign).length == 2 &&
363         is(ParameterTypeTuple!(T.opIndexAssign)[1] : index_t)
364     ) {
365         const idxobjargproc opIndexAssign_sequence_wrap = &opindexassign_sequence_pyfunc!(T).func;
366     } else {
367         const idxobjargproc opIndexAssign_sequence_wrap = null;
368     }
369 }
370
371 template opIndex_mapping_wrap(T) {
372     static if (
373         is(typeof(&T.opIndex)) &&
374         (ParameterTypeTuple!(T.opIndex).length > 1 ||
375         !is(ParameterTypeTuple!(T.opIndex)[0] : index_t))
376     ) {
377         const binaryfunc opIndex_mapping_wrap = &opindex_mapping_pyfunc!(T).func;
378     } else {
379         const binaryfunc opIndex_mapping_wrap = null;
380     }
381 }
382
383 template opIndexAssign_mapping_wrap(T) {
384     static if (
385         is(typeof(&T.opIndexAssign)) &&
386         (ParameterTypeTuple!(T.opIndex).length > 2 ||
387         !is(ParameterTypeTuple!(T.opIndex)[1] : index_t))
388     ) {
389         const objobjargproc opIndexAssign_mapping_wrap = &opindexassign_mapping_pyfunc!(T).func;
390     } else {
391         const objobjargproc opIndexAssign_mapping_wrap = null;
392     }
393 }
394
395 template opSlice_wrap(T) {
396     static if (
397         is(typeof(&T.opSlice)) &&
398         ParameterTypeTuple!(T.opSlice).length == 2 &&
399         is(ParameterTypeTuple!(T.opSlice)[0] : index_t) &&
400         is(ParameterTypeTuple!(T.opSlice)[1] : index_t)
401     ) {
402         const idxidxargfunc opSlice_wrap = &opslice_pyfunc!(T).func;
403     } else {
404         const idxidxargfunc opSlice_wrap = null;
405     }
406 }
407
408 template opSliceAssign_wrap(T) {
409     static if (
410         is(typeof(&T.opSlice)) &&
411         ParameterTypeTuple!(T.opSlice).length == 3 &&
412         is(ParameterTypeTuple!(T.opSlice)[1] : index_t) &&
413         is(ParameterTypeTuple!(T.opSlice)[2] : index_t)
414     ) {
415         const idxidxobjargproc opSliceAssign_wrap = &opsliceassign_pyfunc!(T).func;
416     } else {
417         const idxidxobjargproc opSliceAssign_wrap = null;
418     }
419 }
420
421 template opAdd_wrap(T) {
422     static if (is(typeof(&T.opAdd))) {
423         const binaryfunc opAdd_wrap = &opfunc_binary_wrap!(T, T.opAdd).func;
424     } else {
425         const binaryfunc opAdd_wrap = null;
426     }
427 }
428
429 template opSub_wrap(T) {
430     static if (is(typeof(&T.opSub))) {
431         const binaryfunc opSub_wrap = &opfunc_binary_wrap!(T, T.opSub).func;
432     } else {
433         const binaryfunc opSub_wrap = null;
434     }
435 }
436
437
438 template opMul_wrap(T) {
439     static if (is(typeof(&T.opMul))) {
440         const binaryfunc opMul_wrap = &opfunc_binary_wrap!(T, T.opMul).func;
441     } else {
442         const binaryfunc opMul_wrap = null;
443     }
444 }
445
446
447 template opDiv_wrap(T) {
448     static if (is(typeof(&T.opDiv))) {
449         const binaryfunc opDiv_wrap = &opfunc_binary_wrap!(T, T.opDiv).func;
450     } else {
451         const binaryfunc opDiv_wrap = null;
452     }
453 }
454
455
456 template opMod_wrap(T) {
457     static if (is(typeof(&T.opMod))) {
458         const binaryfunc opMod_wrap = &opfunc_binary_wrap!(T, T.opMod).func;
459     } else {
460         const binaryfunc opMod_wrap = null;
461     }
462 }
463
464
465 template opAnd_wrap(T) {
466     static if (is(typeof(&T.opAnd))) {
467         const binaryfunc opAnd_wrap = &opfunc_binary_wrap!(T, T.opAnd).func;
468     } else {
469         const binaryfunc opAnd_wrap = null;
470     }
471 }
472
473
474 template opOr_wrap(T) {
475     static if (is(typeof(&T.opOr))) {
476         const binaryfunc opOr_wrap = &opfunc_binary_wrap!(T, T.opOr).func;
477     } else {
478         const binaryfunc opOr_wrap = null;
479     }
480 }
481
482
483 template opXor_wrap(T) {
484     static if (is(typeof(&T.opXor))) {
485         const binaryfunc opXor_wrap = &opfunc_binary_wrap!(T, T.opXor).func;
486     } else {
487         const binaryfunc opXor_wrap = null;
488     }
489 }
490
491
492 template opShl_wrap(T) {
493     static if (is(typeof(&T.opShl))) {
494         const binaryfunc opShl_wrap = &opfunc_binary_wrap!(T, T.opShl).func;
495     } else {
496         const binaryfunc opShl_wrap = null;
497     }
498 }
499
500
501 template opShr_wrap(T) {
502     static if (is(typeof(&T.opShr))) {
503         const binaryfunc opShr_wrap = &opfunc_binary_wrap!(T, T.opShr).func;
504     } else {
505         const binaryfunc opShr_wrap = null;
506     }
507 }
508
509
510 template opUShr_wrap(T) {
511     static if (is(typeof(&T.opUShr))) {
512         const binaryfunc opUShr_wrap = &opfunc_binary_wrap!(T, T.opUShr).func;
513     } else {
514         const binaryfunc opUShr_wrap = null;
515     }
516 }
517
518
519 template opCat_wrap(T) {
520     static if (is(typeof(&T.opCat))) {
521         const binaryfunc opCat_wrap = &opfunc_binary_wrap!(T, T.opCat).func;
522     } else {
523         const binaryfunc opCat_wrap = null;
524     }
525 }
526
527
528 template opAddAssign_wrap(T) {
529     static if (is(typeof(&T.opAddAssign))) {
530         const binaryfunc opAddAssign_wrap = &opfunc_binary_wrap!(T, T.opAddAssign).func;
531     } else {
532         const binaryfunc opAddAssign_wrap = null;
533     }
534 }
535
536
537 template opSubAssign_wrap(T) {
538     static if (is(typeof(&T.opSubAssign))) {
539         const binaryfunc opSubAssign_wrap = &opfunc_binary_wrap!(T, T.opSubAssign).func;
540     } else {
541         const binaryfunc opSubAssign_wrap = null;
542     }
543 }
544
545
546 template opMulAssign_wrap(T) {
547     static if (is(typeof(&T.opMulAssign))) {
548         const binaryfunc opMulAssign_wrap = &opfunc_binary_wrap!(T, T.opMulAssign).func;
549     } else {
550         const binaryfunc opMulAssign_wrap = null;
551     }
552 }
553
554
555 template opDivAssign_wrap(T) {
556     static if (is(typeof(&T.opDivAssign))) {
557         const binaryfunc opDivAssign_wrap = &opfunc_binary_wrap!(T, T.opDivAssign).func;
558     } else {
559         const binaryfunc opDivAssign_wrap = null;
560     }
561 }
562
563
564 template opModAssign_wrap(T) {
565     static if (is(typeof(&T.opModAssign))) {
566         const binaryfunc opModAssign_wrap = &opfunc_binary_wrap!(T, T.opModAssign).func;
567     } else {
568         const binaryfunc opModAssign_wrap = null;