Changeset 26

Show
Ignore:
Timestamp:
07/05/06 17:09:25 (2 years ago)
Author:
KirkMcDonald
Message:

Function wrapping improvements, and some automatic operator overload wrapping.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/build_manifest.py

    r24 r26  
    66    '.marks', # jEdit bookmark files 
    77    '.map', # Created automatically by the DMD compiler; needn't distribute. 
     8    '.swp', # Vim swap files 
    89  ] 
    910 
  • trunk/dcompiler.py

    r24 r26  
    3131    'exception.d', 
    3232    'ftype.d', 
     33    'func_wrap.d', 
    3334    'make_object.d', 
    3435    'object.d', 
     36    'op_wrap.d', 
    3537    'pyd.d', 
    3638] 
  • trunk/examples/testdll/testdll.d

    r24 r26  
    4343        writefln("Foo.foo(): i = %s", m_i); 
    4444    } 
     45    Foo opAdd(Foo f) { return new Foo(m_i + f.m_i); } 
    4546    int i() { return m_i; } 
    4647    void i(int j) { m_i = j; } 
     48} 
     49 
     50void iter_test(PyObject* c) { 
     51    Bar b = new Bar(1, 2, 3, 4, 5); 
     52    PyObject* o, res; 
     53    foreach(i; b) { 
     54        o = _py(i); 
     55        res = PyObject_CallFunctionObjArgs(c, o, null); 
     56        Py_DECREF(res); 
     57        Py_DECREF(o); 
     58    } 
     59} 
     60 
     61void delegate() func_test() { 
     62    Foo f = new Foo(20); 
     63    return &f.foo; 
     64} 
     65 
     66class Bar { 
     67    int[] m_a; 
     68    this() { } 
     69    this(int[] i ...) { m_a = i; } 
     70    int opApply(int delegate(inout int) dg) { 
     71        int result = 0; 
     72        for (int i=0; i<m_a.length; ++i) { 
     73            result = dg(m_a[i]); 
     74            if (result) break; 
     75        } 
     76        return result; 
     77    } 
    4778} 
    4879 
     
    5586extern (C) 
    5687export void inittestdll() { 
     88    module_init("testdll"); 
     89 
    5790    def!("foo", foo); 
    5891    // Python does not support function overloading. This allows us to wrap 
     
    6093    def!("foo2", foo, 1, void function(int)); 
    6194    def!("bar", bar); 
    62     // Minimum argument count. 
    63     def!("baz", baz, 0); 
     95    // Default argument support - Now implicit! 
     96    def!("baz", baz); 
    6497    def!("spam", spam); 
    65  
    66     module_init("testdll"); 
     98    def!("iter_test", iter_test); 
     99    def!("func_test", func_test); 
    67100 
    68101    wrapped_class!("Foo", Foo) f; 
  • trunk/infrastructure/pyd/class_wrap.d

    r25 r26  
    2323 
    2424private import python; 
     25 
    2526private import pyd.ctor_wrap; 
    2627private import pyd.def; 
    2728private import pyd.ftype; 
     29private import pyd.func_wrap; 
    2830private import pyd.make_object; 
     31private import pyd.op_wrap; 
     32 
    2933private import std.string; 
     34 
     35template DPyObject_HEAD(T) { 
     36    mixin PyObject_HEAD; 
     37    T d_obj; 
     38} 
    3039 
    3140/// The class object, a subtype of PyObject 
     
    3342    extern(C) 
    3443    struct wrapped_class_object { 
    35         mixin PyObject_HEAD; 
    36         T d_obj; 
     44        mixin DPyObject_HEAD!(T); 
    3745    } 
    3846} 
     
    4654        0,                            /*ob_size*/ 
    4755        null,                         /*tp_name*/ 
    48         (wrapped_class_object!(T)).sizeof, /*tp_basicsize*/ 
     56        0,                            /*tp_basicsize*/ 
    4957        0,                            /*tp_itemsize*/ 
    5058        &wrapped_methods!(T).wrapped_dealloc, /*tp_dealloc*/ 
     
    5361        null,                         /*tp_setattr*/ 
    5462        null,                         /*tp_compare*/ 
    55         &wrapped_methods!(T).wrapped_repr, /*tp_repr*/ 
     63        null,                        /*tp_repr*/ 
    5664        null,                         /*tp_as_number*/ 
    5765        null,                         /*tp_as_sequence*/ 
     
    6371        null,                         /*tp_setattro*/ 
    6472        null,                         /*tp_as_buffer*/ 
    65         Py_TPFLAGS_DEFAULT,          /*tp_flags*/ 
     73        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 
    6674        null,                         /*tp_doc*/ 
    6775        null,                     /* tp_traverse */ 
     
    114122        wrap_object* self = cast(wrap_object*)_self; 
    115123        if (self.d_obj !is null) { 
    116             wrap_class_instances!(T)[self.d_obj] = wrap_class_instances!(T)[self.d_obj] - 1
    117             if (wrap_class_instances!(T)[self.d_obj] == 0) { 
     124            wrap_class_instances!(T)[self.d_obj]--
     125            if (wrap_class_instances!(T)[self.d_obj] <= 0) { 
    118126                wrap_class_instances!(T).remove(self.d_obj); 
    119127            } 
     
    121129        self.ob_type.tp_free(self); 
    122130    } 
    123  
     131
     132 
     133template wrapped_repr(T) { 
     134    alias wrapped_class_object!(T) wrap_object; 
    124135    /// The default repr method calls the class's toString. 
    125136    extern(C) 
    126     PyObject* wrapped_repr(PyObject* _self) { 
     137    PyObject* repr(PyObject* _self) { 
    127138        wrap_object* self = cast(wrap_object*)_self; 
    128139        char[] repr = self.d_obj.toString(); 
     
    137148    extern(C) 
    138149    int init(PyObject* self, PyObject* args, PyObject* kwds) { 
    139         // TODO: Provide better constructor support... 
    140150        T t = new T; 
    141151        (cast(wrap_object*)self).d_obj = t; 
     
    190200 
    191201// The set of all instances of this class that are passed into Python. Keeping 
    192 // references here in D is needed to keep the GC happy. 
    193 // XXX: This currently fails if the same reference is held by multiple Python 
    194 // objects. 
     202// references here in D is needed to keep the GC happy. The integer value is 
     203// used to make this a sort of poor man's multiset. 
    195204template wrap_class_instances(T) { 
    196205    int[T] wrap_class_instances; 
     
    237246         *        if more than one function has the same name as this one. 
    238247         */ 
    239         template def(char[] name, alias fn, uint MIN_ARGS = NumberOfArgs!(typeof(&fn)), fn_t=typeof(&fn)) { 
     248        template def(char[] name, alias fn, uint MIN_ARGS = MIN_ARGS!(fn), fn_t=typeof(&fn)) { 
    240249            static void def() { 
    241250                static PyMethodDef empty = { null, null, 0, null }; 
    242                 wrapped_method_list!(T)[length-1].ml_name = name ~ \0
    243                 wrapped_method_list!(T)[length-1].ml_meth = 
    244                     cast(PyCFunction)&func_wrap!(fn, MIN_ARGS, T, fn_t).func; 
    245                 wrapped_method_list!(T)[length-1].ml_flags = METH_VARARGS; 
    246                 wrapped_method_list!(T)[length-1].ml_doc = ""; 
    247                 wrapped_method_list!(T) ~= empty; 
     251                alias wrapped_method_list!(T) list
     252                list[length-1].ml_name = name ~ \0; 
     253                list[length-1].ml_meth = &func_wrap!(fn, MIN_ARGS, T, fn_t).func; 
     254                list[length-1].ml_flags = METH_VARARGS; 
     255                list[length-1].ml_doc = ""; 
     256                list ~= empty; 
    248257                // It's possible that appending the empty item invalidated the 
    249258                // pointer in the type struct, so we renew it here. 
    250                 wrapped_class_type!(T).tp_methods = 
    251                     wrapped_method_list!(T); 
     259                wrapped_class_type!(T).tp_methods = list; 
    252260            } 
    253261        } 
     
    308316void finalize_class(CLS) (CLS cls) { 
    309317    alias typeof(cls.t) T; 
     318    alias wrapped_class_type!(T) type; 
    310319    const char[] name = CLS._name; 
    311320     
     
    313322    char[] module_name = .toString(PyModule_GetName(DPy_Module_p)); 
    314323     
    315     wrapped_class_type!(T).ob_type    = PyType_Type_p; 
    316     wrapped_class_type!(T).tp_doc     = name ~ " objects" ~ \0; 
    317     wrapped_class_type!(T).tp_new     = &PyType_GenericNew; 
    318     wrapped_class_type!(T).tp_methods = wrapped_method_list!(T); 
    319     wrapped_class_type!(T).tp_name = 
    320         module_name ~ "." ~ name ~ \0; 
     324    // Fill in missing values 
     325    type.ob_type      = PyType_Type_p; 
     326    type.tp_basicsize = (wrapped_class_object!(T)).sizeof; 
     327    type.tp_doc       = name ~ " objects" ~ \0; 
     328    //type.tp_new       = &PyType_GenericNew; 
     329    type.tp_repr      = &wrapped_repr!(T).repr; 
     330    type.tp_methods   = wrapped_method_list!(T); 
     331    type.tp_name      = module_name ~ "." ~ name ~ \0; 
     332    if (wrapped_class_as_number!(T) != PyNumberMethods.init) { 
     333        type.tp_as_number = &wrapped_class_as_number!(T); 
     334    } 
    321335     
    322336    // If a ctor wasn't supplied, try the default. 
    323     if (wrapped_class_type!(T).tp_init is null) { 
    324         wrapped_class_type!(T).tp_init = 
    325             &wrapped_init!(T).init; 
    326     } 
    327     if (PyType_Ready(&wrapped_class_type!(T)) < 0) { 
     337    if (type.tp_init is null) { 
     338        type.tp_init = &wrapped_init!(T).init; 
     339    } 
     340    if (PyType_Ready(&type) < 0) { 
    328341        // XXX: This will probably crash the interpreter, as it isn't normally 
    329342        // caught and translated. 
    330343        throw new Exception("Couldn't ready wrapped type!"); 
    331344    } 
    332     Py_INCREF(cast(PyObject*)&wrapped_class_type!(T)); 
    333     PyModule_AddObject(DPy_Module_p, name, cast(PyObject*)&wrapped_class_type!(T)); 
     345    Py_INCREF(cast(PyObject*)&type); 
     346    PyModule_AddObject(DPy_Module_p, name, cast(PyObject*)&type); 
    334347    is_wrapped!(T) = true; 
    335348} 
  • trunk/infrastructure/pyd/def.d

    r25 r26  
    2323 
    2424private import python; 
     25 
     26private import pyd.class_wrap; 
     27private import pyd.dg_convert; 
     28private import pyd.exception; 
     29private import pyd.ftype; 
     30private import pyd.func_wrap; 
    2531private import pyd.make_object; 
    26 private import pyd.object; 
    27 private import pyd.ftype; 
    28 private import pyd.exception; 
    29 private import pyd.dg_convert; 
    30 private import pyd.class_wrap; 
     32 
    3133private import std.string; 
    3234 
     
    7577 *It's greater than 10!) 
    7678 */ 
    77 template def(char[] name, alias fn, uint MIN_ARGS = NumberOfArgs!(typeof(&fn)), fn_t=typeof(&fn)) { 
     79template def(char[] name, alias fn, uint MIN_ARGS = MIN_ARGS!(fn), fn_t=typeof(&fn)) { 
    7880    void def() { 
    79         static PyMethodDef empty = { null, null, 0, null }; 
    80         module_global_methods[length-1].ml_name = name ~ \0; 
    81         module_global_methods[length-1].ml_meth = 
    82             cast(PyCFunction)&func_wrap!(fn, MIN_ARGS, void, fn_t).func; 
    83         module_global_methods[length-1].ml_flags = METH_VARARGS; 
    84         module_global_methods[length-1].ml_doc = ""; 
    85         module_global_methods ~= empty; 
     81        fn_t fptr = &fn; 
     82        PyObject* func = DPyFunc_FromDG!(fn_t, MIN_ARGS)(fptr); 
     83        PyObject_SetAttrString(DPy_Module_p, name ~ \0, func); 
     84        Py_DECREF(func); 
    8685    } 
    8786} 
     
    9695} 
    9796 
    98 template func_wrap(alias real_fn, uint MIN_ARGS, C=void, fn_t=typeof(&real_fn)) { 
    99     //typeof(&r_fn) fn = &r_fn; 
    100     //alias typeof(&real_fn) fn_t; 
    101     const uint MAX_ARGS = NumberOfArgs!(fn_t); 
    102     alias ReturnType!(fn_t) RetType; 
    103     extern (C) 
    104     PyObject* func(PyObject* self, PyObject* args) { 
    105         PyObject* ret; 
    106  
    107         // If C is specified, then this is a method call. We need to pull out 
    108         // the object in self and turn the member function pointer in real_fn 
    109         // into a delegate. This conversion is done with a dirty hack; see 
    110         // dg_convert.d. 
    111         static if (!is(C == void)) { 
    112             // Didn't pass a "self" parameter! Ack! 
    113             if (self is null) { 
    114                 PyErr_SetString(PyExc_TypeError, "Wrapped method didn't get a 'self' parameter."); 
    115                 return null; 
    116             } 
    117             C instance = (cast(wrapped_class_object!(C)*)self).d_obj; 
    118             fn_to_dg!(fn_t) fn = dg_wrapper!(C, fn_t)(instance, &real_fn); 
    119         // If C is not specified, then this is just a normal function call. 
    120         } else { 
    121             fn_t fn = &real_fn; 
    122         } 
    123  
    124         // Sanity check! 
    125         int ARGS = 0; 
    126         // This can make it more convenient to call this with 0 args. 
    127         if (args !is null) 
    128             ARGS = PyObject_Length(args); 
    129         if (ARGS < MIN_ARGS || ARGS > MAX_ARGS) { 
    130             PyErr_SetString(PyExc_TypeError, "Wrong number of arguments. Got " ~ toString(ARGS) ~ ", expected between " ~ toString(MIN_ARGS) ~ "-" ~ toString(MAX_ARGS) ~ " args."); 
    131             return null; 
    132         } 
    133          
    134         try { /* begin try */ 
    135          
    136         static if (MIN_ARGS <= 0 && MAX_ARGS >= 0) { 
    137             if (ARGS == 0) { 
    138                 // If the return type is void... 
    139                 static if (is(RetType : void)) { 
    140                     fn(); 
    141                     // Return Py_None 
    142                     Py_INCREF(Py_None); 
    143                     ret = Py_None; 
    144                 } else { 
    145                     // Otherwise, return a conversion of the return value 
    146                     ret = _py( fn() ); 
    147                 } 
    148             } 
    149         } static if (MIN_ARGS <= 1 && MAX_ARGS >= 1) { 
    150             if (ARGS == 1) { 
    151                 // See, this ugly code works like this: 
    152                 // (1) _py takes the return type of the wrapped function, and 
    153                 // converts it to a PyObject*, which is passed straight back into 
    154                 // Python. 
    155                 // (2) fn is the wrapped function. Each of its arguments take the 
    156                 // form: 
    157                 // (3) d_type is a template function. It converts a PyObject* into 
    158                 // a reasonable D type. The template argument is the type to 
    159                 // convert to. The function argument is the PyObject* to convert. 
    160                 // (4) ArgType derives the type of an argument to the function. It 
    161                 // (therefore) is used to pass the correct type into d_type's 
    162                 // template argument. 
    163                 // This pattern is repeated umpteen times, as each number of 
    164                 // function arguments requires its own statement TWICE, as void 
    165                 // return types must be handled differently. 
    166                 static if (is(RetType : void)) { 
    167                     // Call with void return type 
    168                     fn( 
    169                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)) 
    170                     ); 
    171                     // Return Py_None 
    172                     Py_INCREF(Py_None); 
    173                     ret = Py_None; 
    174                 } else { 
    175                     // Capture return value 
    176                     ret = _py( fn( 
    177                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)) 
    178                     ) ); 
    179                 } 
    180             } 
    181         } static if (MIN_ARGS <= 2 && MAX_ARGS >= 2) { 
    182             if (ARGS == 2) { 
    183                 static if (is(RetType : void)) { 
    184                     fn( 
    185                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    186                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)) 
    187                     ); 
    188                     Py_INCREF(Py_None); 
    189                     ret = Py_None; 
    190                 } else { 
    191                     ret = _py( fn( 
    192                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    193                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)) 
    194                     ) ); 
    195                 } 
    196             } 
    197         } static if (MIN_ARGS <= 3 && MAX_ARGS >= 3) { 
    198             if (ARGS == 3) { 
    199                 static if (is(RetType : void)) { 
    200                     fn( 
    201                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    202                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    203                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)) 
    204                     ); 
    205                     Py_INCREF(Py_None); 
    206                     ret = Py_None; 
    207                 } else { 
    208                     ret = _py( fn( 
    209                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    210                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    211                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)) 
    212                     ) ); 
    213                 } 
    214             } 
    215         } static if (MIN_ARGS <= 4 && MAX_ARGS >= 4) { 
    216             if (ARGS == 4) { 
    217                 static if (is(RetType : void)) { 
    218                     fn( 
    219                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    220                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    221                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    222                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)) 
    223                     ); 
    224                     Py_INCREF(Py_None); 
    225                     ret = Py_None; 
    226                 } else { 
    227                     ret = _py( fn( 
    228                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    229                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    230                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    231                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)) 
    232                     ) ); 
    233                 } 
    234             } 
    235         } static if (MIN_ARGS <= 5 && MAX_ARGS >= 5) { 
    236             if (ARGS == 5) { 
    237                 static if (is(RetType : void)) { 
    238                     fn( 
    239                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    240                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    241                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    242                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    243                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)) 
    244                     ); 
    245                     Py_INCREF(Py_None); 
    246                     ret = Py_None; 
    247                 } else { 
    248                     ret = _py( fn( 
    249                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    250                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    251                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    252                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    253                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)) 
    254                     ) ); 
    255                 } 
    256             } 
    257         } static if (MIN_ARGS <= 6 && MAX_ARGS >= 6) { 
    258             if (ARGS == 6) { 
    259                 static if (is(RetType : void)) { 
    260                     fn( 
    261                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    262                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    263                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    264                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    265                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    266                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)) 
    267                     ); 
    268                     Py_INCREF(Py_None); 
    269                     ret = Py_None; 
    270                 } else { 
    271                     ret = _py( fn( 
    272                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    273                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    274                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    275                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    276                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    277                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)) 
    278                     ) ); 
    279                 } 
    280             } 
    281         } static if (MIN_ARGS <= 7 && MAX_ARGS >= 7) { 
    282             if (ARGS == 7) { 
    283                 static if (is(RetType : void)) { 
    284                     fn( 
    285                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    286                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    287                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    288                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    289                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    290                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    291                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)) 
    292                     ); 
    293                     Py_INCREF(Py_None); 
    294                     ret = Py_None; 
    295                 } else { 
    296                     ret = _py( fn( 
    297                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    298                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    299                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    300                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    301                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    302                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    303                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)) 
    304                     ) ); 
    305                 } 
    306             } 
    307         } static if (MIN_ARGS <= 8 && MAX_ARGS >= 8) { 
    308             if (ARGS == 8) { 
    309                 static if (is(RetType : void)) { 
    310                     fn( 
    311                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    312                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    313                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    314                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    315                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    316                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    317                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    318                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)) 
    319                     ); 
    320                     Py_INCREF(Py_None); 
    321                     ret = Py_None; 
    322                 } else { 
    323                     ret = _py( fn( 
    324                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    325                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    326                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    327                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    328                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    329                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    330                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    331                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)) 
    332                     ) ); 
    333                 } 
    334             } 
    335         } static if (MIN_ARGS <= 9 && MAX_ARGS >= 9) { 
    336             if (ARGS == 9) { 
    337                 static if (is(RetType : void)) { 
    338                     fn( 
    339                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    340                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    341                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    342                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    343                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    344                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    345                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    346                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)), 
    347                         d_type!(ArgType!(fn_t, 9))(PyTuple_GetItem(args, 8)) 
    348                     ); 
    349                     Py_INCREF(Py_None); 
    350                     ret = Py_None; 
    351                 } else { 
    352                     ret = _py( fn( 
    353                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    354                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    355                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    356                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    357                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    358                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    359                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    360                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)), 
    361                         d_type!(ArgType!(fn_t, 9))(PyTuple_GetItem(args, 8)) 
    362                     ) ); 
    363                 } 
    364             } 
    365         } static if (MIN_ARGS <= 10 && MAX_ARGS >= 10) { 
    366             if (ARGS == 10) { 
    367                 static if (is(RetType : void)) { 
    368                     fn( 
    369                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    370                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    371                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    372                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    373                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    374                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    375                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    376                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)), 
    377                         d_type!(ArgType!(fn_t, 9))(PyTuple_GetItem(args, 8)), 
    378                         d_type!(ArgType!(fn_t, 10))(PyTuple_GetItem(args, 9)) 
    379                     ); 
    380                     Py_INCREF(Py_None); 
    381                     ret = Py_None; 
    382                 } else { 
    383                     ret = _py( fn( 
    384                         d_type!(ArgType!(fn_t, 1))(PyTuple_GetItem(args, 0)), 
    385                         d_type!(ArgType!(fn_t, 2))(PyTuple_GetItem(args, 1)), 
    386                         d_type!(ArgType!(fn_t, 3))(PyTuple_GetItem(args, 2)), 
    387                         d_type!(ArgType!(fn_t, 4))(PyTuple_GetItem(args, 3)), 
    388                         d_type!(ArgType!(fn_t, 5))(PyTuple_GetItem(args, 4)), 
    389                         d_type!(ArgType!(fn_t, 6))(PyTuple_GetItem(args, 5)), 
    390                         d_type!(ArgType!(fn_t, 7))(PyTuple_GetItem(args, 6)), 
    391                         d_type!(ArgType!(fn_t, 8))(PyTuple_GetItem(args, 7)), 
    392                         d_type!(ArgType!(fn_t, 9))(PyTuple_GetItem(args, 8)), 
    393                         d_type!(ArgType!(fn_t, 10))(PyTuple_GetItem(args, 9)) 
    394                     ) ); 
    395                 } 
    396             } 
    397         } 
    398          
    399         } /* end try */ 
    400         // A Python exception was raised and duly re-thrown as a D exception. 
    401         // It should now be re-raised as a Python exception. 
    402         catch (PythonException e) { 
    403             PyErr_Restore(e.type(), e.value(), e.traceback()); 
    404             return null; 
    405         } 
    406         // A D exception was raised and should be translated into a meaningful 
    407         // Python exception. 
    408         catch (Exception e) { 
    409             PyErr_SetString(PyExc_RuntimeError, "D Exception: " ~ e.classinfo.name ~ ": " ~ e.msg ~ \0); 
    410             return null; 
    411         } 
    412         return ret; 
    413     } 
    414 } 
    415  
  • trunk/infrastructure/pyd/ftype.d

    r24 r26  
    1 /* 
    2 Copyright (c) 2006 Daniel Keep, Tomasz Stachowiak 
    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  
    231/** 
    24  * This module contains templates for inferring the number of arguments, 
     2 * This module contains template for inferring the number of arguments, 
    253 * the return type, and argument types of an arbitrary function pointer. 
    264 *  
    27  * Portions of this module were automatically generated by Python modules. 
    28  * 
    29  * Authors: Daniel Keep, Tomasz Stachowiak 
    30  * Date: $(DATETIME) 
     5 * This module was automatically generated by ftype.py 
     6 *  
     7 * Written by Daniel Keep. 
     8 * Released to public domain—share and enjoy (just leave my name in it, 
     9 * pretty please). 
    3110 */ 
    3211module pyd.ftype; 
     
    137116} 
    138117 
     118template 
     119NumberOfArgsSwitchT(Tf) 
     120{ 
     121    static if( is( typeof(*Tf) == function ) ) 
     122        alias NumberOfArgsT!(Tf).type type; 
     123    else static if( is( Tf U == delegate ) ) 
     124        alias NumberOfArgsSwitchT!(U*).type type; 
     125    else static if( (is( T == class ) || is( T == struct )) && is(typeof(&T.opCall)) ) 
     126        alias NumberOfArgsSwitchT!(typeof(&T.opCall)).type type; 
     127} 
     128 
    139129/** 
    140  * Derives the number of arguments the passed function type accepts. It only 
    141  * works on functions with 10 or fewer arguments. 
     130 * This template will attempt to determine the number of arguments the 
     131 * supplied function pointer or delegate type takes.  It supports a maximum of 
     132 * 10 arguments. 
     133 * 
     134 * Example: 
     135 * ---------------------------------------- 
     136 * void fnWithThreeArgs(byte a, short b, int c) {} 
     137 * const uint numArgs = NumberOfArgs!(typeof(&fnWithThreeArgs)); 
     138 * ---------------------------------------- 
    142139 */ 
    143140public 
     
    145142NumberOfArgs(Tf) 
    146143{ 
    147     const uint NumberOfArgs = ArglenConvT!(NumberOfArgsT!(Tf).type); 
    148 
    149  
    150 // Thanks to Tomasz Stachowiak for the Deref and ReturnType templates! 
    151 template Deref(T) { 
    152     alias typeof(*T) Deref; 
     144    const uint NumberOfArgs = ArglenConvT!(NumberOfArgsSwitchT!(Tf).type); 
     145
     146 
     147template 
     148ReturnTypeT(Tf) 
     149
     150    private Tf fptr; 
     151    static if( is( typeof(*Tf) U == function ) ) 
     152        alias U type; 
     153    else static if( is( Tf U == delegate ) ) 
     154        alias ReturnType!(U*) type; 
     155    else static if( (is( T == class ) || is( T == struct )) && is(typeof(&T.opCall)) ) 
     156        alias ReturnTypeT!(typeof(&T.opCall)).type type; 
     157    else 
     158        static assert(false, "ReturnType argument must be function pointer" 
     159                " or delegate."); 
    153160} 
    154161 
    155162/** 
    156  * Derives the return type of the passed function type. 
     163 * This template will attempt to discern the return type of the supplied 
     164 * function pointer or delegate type.  It supports callables with a maximum of 
     165 * 10 arguments. 
     166 * 
     167 * Example: 
     168 * ---------------------------------------- 
     169 * uint returnsANumber() { return 42; } 
     170 * alias ReturnType!(typeof(&returnsANumber)) RType; // RType == uint 
     171 * ---------------------------------------- 
    157172 */ 
    158173public 
    159 template ReturnType(T) { 
    160     static if (is(Deref!(T) U == function)) { 
    161         alias U ReturnType; 
    162     } else static if (is(Deref!(T) U == delegate)) { 
    163         alias ReturnType!(U) ReturnType; 
    164     } else static assert (false); 
     174template 
     175ReturnType(Tf) 
     176
     177    alias ReturnTypeT!(Tf).type ReturnType; 
    165178} 
    166179 
     
    502515    private Tf fptr; 
    503516    static if( n == 1 ) 
    504         alias typeof(Arg1TypeT(Tf)) type; 
     517        alias typeof(Arg1TypeT(fptr)) type; 
    505518    else static if( n == 2 ) 
    506         alias typeof(Arg2TypeT(Tf)) type; 
     519        alias typeof(Arg2TypeT(fptr)) type; 
    507520    else static if( n == 3 ) 
    508         alias typeof(Arg3TypeT(Tf)) type; 
     521        alias typeof(Arg3TypeT(fptr)) type; 
    509522    else static if( n == 4 ) 
    510         alias typeof(Arg4TypeT(Tf)) type; 
     523        alias typeof(Arg4TypeT(fptr)) type; 
    511524    else static if( n == 5 ) 
    512         alias typeof(Arg5TypeT(Tf)) type; 
     525        alias typeof(Arg5TypeT(fptr)) type; 
    513526    else static if( n == 6 ) 
    514         alias typeof(Arg6TypeT(Tf)) type; 
     527        alias typeof(Arg6TypeT(fptr)) type; 
    515528    else static if( n == 7 ) 
    516         alias typeof(Arg7TypeT(Tf)) type; 
     529        alias typeof(Arg7TypeT(fptr)) type; 
    517530    else static if( n == 8 ) 
    518         alias typeof(Arg8TypeT(Tf)) type; 
     531        alias typeof(Arg8TypeT(fptr)) type; 
    519532    else static if( n == 9 ) 
    520         alias typeof(Arg9TypeT(Tf)) type; 
     533        alias typeof(Arg9TypeT(fptr)) type; 
    521534    else static if( n == 10 ) 
    522         alias typeof(Arg10TypeT(Tf)) type; 
     535        alias typeof(Arg10TypeT(fptr)) type; 
    523536    else 
    524         { static assert(false); } 
     537        static assert(false, 
     538                "Maximum of 10 arguments supported."); 
     539
     540 
     541template 
     542ArgTypeSwitchT(Tf, uint n) 
     543
     544    static if( is( typeof(*Tf) == function ) ) 
     545        alias ArgTypeT!(Tf, n).type type; 
     546    else static if( is( Tf U == delegate ) ) 
     547        alias ArgTypeSwitchT!(U*, n).type type; 
     548    else static if( (is( T == class ) || is( T == struct )) && is(typeof(&T.opCall)) ) 
     549        alias ArgTypeSwitchT!(typeof(&T.opCall)).type type; 
     550    else 
     551        static assert(false, "ArgType argument must be a function pointer" 
     552                " or a delegate."); 
    525553} 
    526554 
    527555/** 
    528  * Derives the type of an individual argument of function Tf. 
    529  * Params: 
    530  *      Tf = A function pointer type 
    531  *      n = The 1-indexed function argument to get the type of, e.g.: 
    532  *          $(D_CODE int func(int, char, real); 
    533  *static assert( is(char == _ArgType(&func, 2)) );) 
     556 * This template will attempt to extract the type of the nth argument of the 
     557 * given function pointer or delegate type.  It supports callables with up to 
     558 * 10 arguments. 
     559 * 
     560 * Example: 
     561 * ---------------------------------------- 
     562 * void intShortBool(int a, short b, bool c) {} 
     563 * alias ArgType!(typeof(&intShortBool), 2) TArg2; // TArg2 == short 
     564 * ---------------------------------------- 
    534565 */ 
    535566public 
     
    537568ArgType(Tf, uint n) 
    538569{ 
    539     alias ArgTypeT!(Tf, n).type ArgType; 
    540 
    541  
     570    alias ArgTypeSwitchT!(Tf, n).type ArgType; 
     571
     572 
     573template MIN_ARGS_T(alias fn) { 
     574    alias typeof(&fn) fn_t; 
     575    static if (is(typeof(fn()))) 
     576        const uint MIN_ARGS = 0; 
     577    else static if (is(typeof(fn(ArgType!(fn_t, 1).init)))) 
     578        const uint MIN_ARGS = 1; 
     579    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init)))) 
     580        const uint MIN_ARGS = 2; 
     581    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init)))) 
     582        const uint MIN_ARGS = 3; 
     583    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init)))) 
     584        const uint MIN_ARGS = 4; 
     585    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init)))) 
     586        const uint MIN_ARGS = 5; 
     587    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init)))) 
     588        const uint MIN_ARGS = 6; 
     589    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init)))) 
     590        const uint MIN_ARGS = 7; 
     591    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init)))) 
     592        const uint MIN_ARGS = 8; 
     593    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init, ArgType!(fn_t, 9).init)))) 
     594        const uint MIN_ARGS = 9; 
     595    else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init, ArgType!(fn_t, 9).init, ArgType!(fn_t, 10).init)))) 
     596        const uint MIN_ARGS = 10; 
     597
     598 
     599/** 
     600 * This template will attempt to determine the minimum number of arguments a 
     601 * function can accept. (Written by Kirk McDonald.) Note that this accepts an 
     602 * alias parameter rather than a function pointer type, as the function and 
     603 * delegate types contain no information about default arguments. 
     604 */ 
     605public 
     606template MIN_ARGS(alias fn) { 
     607    alias MIN_ARGS_T!(fn).MIN_ARGS MIN_ARGS; 
     608
     609 
     610/* *** Unit tests *** */ 
     611