Changeset 40

Show
Ignore:
Timestamp:
10/24/06 01:24:13 (2 years ago)
Author:
KirkMcDonald
Message:

Meta-programming library replaced; large re-write. StackThreads? updated to 0.3.2. Iteration updates.

Files:

Legend:

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

    r37 r40  
    3232    'dpyobject.d', 
    3333    'exception.d', 
    34     'ftype.d', 
     34#    'ftype.d', 
    3535    'func_wrap.d', 
    3636    'iteration.d', 
     
    3838    'op_wrap.d', 
    3939    'pyd.d', 
    40     'tuples.d', 
     40#    'tuples.d', 
    4141] 
    4242 
     
    4545    'stackcontext.d', 
    4646    'stackthread.d', 
     47    'tls.d', 
     48] 
     49 
     50_metaFiles = [ 
     51    'Apply.d', 
     52    'Bind.d', 
     53    'Default.d', 
     54    'Demangle.d', 
     55    'FuncMeta.d', 
     56    'Instantiate.d', 
     57    'Nameof.d', 
     58    'Tuple.d', 
     59    'Use.d', 
     60    'Util.d', 
     61    'VarArg.d', 
    4762] 
    4863 
     
    162177            if not os.path.isfile(filePath): 
    163178                raise DistutilsPlatformError("Required StackThreads source" 
    164                     "file '%s' is missing." % filePath 
     179                    " file '%s' is missing." % filePath 
     180                ) 
     181            sources.append(filePath) 
     182        # And meta 
     183        for file in _metaFiles: 
     184            filePath = os.path.join(_infraDir, 'meta', file) 
     185            if not os.path.isfile(filePath): 
     186                raise DistutilsPlatformError("Required meta source file" 
     187                    " '%s' is missing." % filePath 
    165188                ) 
    166189            sources.append(filePath) 
     
    380403        self._debugOpt = '-debug=%s' 
    381404        # _defaultOptimizeOpts 
    382         self._defaultOptimizeOpts = ['-debug', '-unittest'
     405        self._defaultOptimizeOpts = ['-debug'
    383406        # _debugOptimizeOpts 
    384         self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-g'] 
     407        self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-unittest', '-g'] 
    385408        # _releaseOptimizeOpts 
    386409        self._releaseOptimizeOpts = ['-version=Optimized', '-release', '-O', '-inline'] 
  • trunk/examples/testdll/testdll.d

    r38 r40  
    66import std.stdio; 
    77 
     8import meta.Tuple; 
     9import meta.Apply; 
     10 
    811void apply_test(int i, char[] s) { 
    912    writefln("%s %s", i, s); 
     
    1114 
    1215void foo() { 
    13     alias tuple!(int, char[]) Tuple; 
    14 //    alias dg_from_tuple!(void, Tuple) dg; 
    15     Tuple t; 
    16 //    Tuple.TypeNo!(0) i = 20; 
    17 //    typeof(Tuple.arg1) j = 30; 
    18     t.arg1 = 20; 
    19     t.arg2 = "Monkey"; 
    20 //    t.arg3 = 5.8; 
    21     apply_tuple_to_fn(t, &apply_test); 
    22      
    23 //    writefln(typeid(ArgType!(dg, 1))); 
    24 //    writefln(typeid(TypeNo!(Tuple, 0))); 
    25 //    writefln(typeid(Tuple.A1)); 
    26 //    writefln(typeid(dg)); 
    27 //    writefln(i, " ", j); 
     16    alias Tuple!(int, char[]) T; 
     17    T t; 
     18    t.val!(0) = 20; 
     19    t.val!(1) = "Monkey"; 
     20    apply(&apply_test, t); 
    2821} 
    2922 
     
    4740    int m_i; 
    4841    this() { } 
    49     this(int i) { m_i = i; } 
    50     this(int i, int j) { m_i = i + j; } 
     42    this(int i) { 
     43        m_i = i; 
     44    } 
     45    this(int i, int j) { 
     46        m_i = i + j; 
     47    } 
    5148    void foo() { 
    5249        writefln("Foo.foo(): i = %s", m_i); 
     
    109106extern (C) 
    110107export void inittestdll() { 
    111     def!(foo, "foo"); 
     108    def!(foo/*, "foo"*/); 
    112109    // Python does not support function overloading. This allows us to wrap 
    113110    // an overloading function under a different name. Note that if the 
     
    132129    wrapped_class!(Foo, "Foo") f; 
    133130    // Constructor wrapping 
    134     f.init!(tuple!(int), tuple!(int, int)); 
     131    f.init!(void function(int), void function(int, int)); 
    135132    // Member function wrapping 
    136133    f.def!(Foo.foo, "foo"); 
  • trunk/html_doc/basics.html

    r39 r40  
    2828<p>Pyd requires Python 2.4 or newer and the latest version of DMD.</p> 
    2929 
    30 <p>At the moment, Pyd is only supported on Windows using the <a href="http://digitalmars.com/d/index.html">DMD</a> compiler. GDC support has been written, but Pyd cannot yet be compiled with GDC. Once GDC support is available, Pyd should work on Linux. Support for Derek Parnell's Build is also planned.</p> 
     30<p>At the moment, Pyd is only supported on Windows using the <a href="http://digitalmars.com/d/index.html">DMD</a> compiler. GDC support has been written, but Pyd cannot yet be compiled with GDC (due to <a href="http://d.puremagic.com/issues/show_bug.cgi?id=311">this bug</a>). Once GDC support is available, Pyd should work on Linux. Support for Derek Parnell's Build is also planned.</p> 
    3131 
    3232<p>Because Pyd is still in development, it is only available via Subversion. The repository is located <a href="http://svn.dsource.org/projects/pyd/trunk">here</a>.</p> 
  • trunk/infrastructure/pyd/class_wrap.d

    r37 r40  
    2222module pyd.class_wrap; 
    2323 
    24 private import python; 
    25  
    26 private import pyd.ctor_wrap; 
    27 private import pyd.def; 
    28 private import pyd.exception; 
    29 private import pyd.ftype; 
    30 private import pyd.func_wrap; 
    31 private import pyd.iteration; 
    32 private import pyd.make_object; 
    33 private import pyd.op_wrap; 
    34 private import pyd.tuples; 
    35  
    36 private import std.string; 
     24private { 
     25    import python; 
     26 
     27    import pyd.ctor_wrap; 
     28    import pyd.def; 
     29    import pyd.exception; 
     30    import pyd.func_wrap; 
     31    import pyd.iteration; 
     32    import pyd.make_object; 
     33    import pyd.op_wrap; 
     34 
     35    import meta.Default; 
     36    import meta.FuncMeta; 
     37    import meta.Tuple; 
     38 
     39    import std.string; 
     40
    3741 
    3842bool[TypeInfo] wrapped_classes; 
     
    168172    // This may be either the getter or the setter 
    169173    alias typeof(&p) p_t; 
     174    alias funcDelegInfoT!(p_t) Info; 
    170175    // This means it's the getter 
    171     static if (NumberOfArgs!(p_t) == 0) { 
     176    static if (Info.numArgs == 0) { 
    172177        alias p_t getter_type; 
    173178        // The setter may return void, or it may return the newly set attribute. 
    174         alias typeof(p(ReturnType!(p_t).init)) function(ReturnType!(p_t)) setter_type; 
     179        alias typeof(p(RetType!(p_t).init)) function(RetType!(p_t)) setter_type; 
    175180    // This means it's the setter 
    176181    } else { 
    177182        alias p_t setter_type; 
    178         alias ArgType!(p_t, 1) function() getter_type; 
     183        alias Info.Meta.ArgType!(0) function() getter_type; 
    179184    } 
    180185} 
     
    258263         *        if more than one function has the same name as this one. 
    259264         */ 
    260         template def(alias fn, char[] name, fn_t=typeof(&fn), uint MIN_ARGS = MIN_ARGS!(fn)) { 
     265        template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) { 
    261266            pragma(msg, "class.def: " ~ name); 
    262267            static void def() { 
     
    315320         * the same number of arguments. 
    316321         */ 
    317         template init(C1=Void, C2=Void, C3=Void, C4=Void, C5=Void, C6=Void, C7=Void, C8=Void, C9=Void, C10=Void) { 
    318             static void init() { 
    319                 wrapped_class_type!(T).tp_init = 
    320                     &wrapped_ctors!(T, tuple!(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)).init_func; 
    321             } 
     322        static void init(C1=int, C2=int, C3=int, C4=int, C5=int, C6=int, C7=int, C8=int, C9=int, C10=int) () { 
     323            wrapped_class_type!(T).tp_init = 
     324                &wrapped_ctors!(T, Tuple!(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10)).init_func; 
     325        } 
     326 
     327        /** 
     328         * Allows selection of alternate opApply overloads. iter_t should be 
     329         * the type of the delegate in the opApply function that the user wants 
     330         * to be the default. 
     331         */ 
     332        static void iter(iter_t) () { 
     333            DPySC_Ready(); 
     334            wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 
     335        } 
     336 
     337        /** 
     338         * Exposes alternate iteration methods, originally intended for use with 
     339         * D's delegate-as-iterator features, as methods returning a Python 
     340         * iterator. 
     341         */ 
     342        static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) () { 
     343            static PyMethodDef empty = { null, null, 0, null }; 
     344            alias wrapped_method_list!(T) list; 
     345            list[length-1].ml_name = name ~ \0; 
     346            list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; 
     347            list[length-1].ml_flags = METH_VARARGS; 
     348            list[length-1].ml_doc = ""; 
     349            list ~= empty; 
     350            // It's possible that appending the empty item invalidated the 
     351            // pointer in the type struct, so we renew it here. 
     352            wrapped_class_type!(T).tp_methods = list; 
    322353        } 
    323354    } 
     
    350381 
    351382    static if (is(typeof(&T.opApply))) { 
    352         DPySC_Ready(); 
    353         type.tp_iter = &wrapped_iter!(T).iter; 
     383        if (type.tp_iter is null) { 
     384            DPySC_Ready(); 
     385            type.tp_iter = &wrapped_iter!(T, T.opApply).iter; 
     386        } 
    354387    } 
    355388     
  • trunk/infrastructure/pyd/ctor_wrap.d

    r37 r40  
    2727private import pyd.func_wrap; 
    2828private import pyd.make_object; 
    29 private import pyd.tuples; 
    3029 
    31 template outer(T) { 
     30private import meta.Tuple; 
     31private import meta.Bind; 
     32private import meta.Instantiate; 
     33 
     34template ctor_redirect(T) { 
    3235    T call_ctor()() { 
    3336        return new T(); 
     
    7578} 
    7679 
    77 // This template accepts a list of "ctor" templates and uses them to wrap a Python tp_init function. 
    78 template wrapped_ctors(T, Tuple) { 
     80// This template accepts a Tuple of (either) function pointer types or other 
     81// Tuples, which each describe a ctor of T, and  uses them to wrap a Python 
     82// tp_init function. 
     83template wrapped_ctors(T, Tu) { 
    7984    alias wrapped_class_object!(T) wrap_object; 
    80     const uint ARGS = Tuple.length; 
     85 
     86    // The user can provide ctor footprints as either function pointer types 
     87    // or as tuples. This converts either to a tuple. 
     88    template ctorAsTuple(T) { 
     89        static if (isTuple!(T)) 
     90            alias T ctorAsTuple; 
     91        else static if (is(typeof(*T) == function)) 
     92            alias getFuncTuple!(T) ctorAsTuple; 
     93    } 
     94 
     95    // This loops through the passed Tuple type and extracts the actual ctor 
     96    // types. 
     97    template loop(uint current, NewTu = EmptyTuple) { 
     98        static if (current == Tu.length || is(typeof(Tu.mix.val!(current))==int)) { 
     99            alias NewTu type; 
     100        } else { 
     101            alias loop!(current+1, NewTu.mix.appendT!(ctorAsTuple!(typeof(Tu.mix.val!(current))))).type type; 
     102        } 
     103    } 
     104    alias loop!(0).type Ctors; 
     105 
     106    // Checks each element of the Ctors tuple against the number of arguments 
     107    // passed in from Python. Then, it calls the ctor with the passed-in 
     108    // arguments. 
     109    int findAndCallCtor(uint current) (PyObject* self, PyObject* args, int argCount) { 
     110        static if (current == Ctors.length) { 
     111            // No match, handle error 
     112            PyErr_SetString(PyExc_TypeError, "Unsupported number of constructor arguments."); 
     113            return -1; 
     114        } else { 
     115            alias typeof(Ctors.mix.val!(current)) Ctor; 
     116            if (Ctor.length == argCount) { 
     117                alias instantiateTemplate!(ctor_redirect!(T).call_ctor, Ctor) fn; 
     118                WrapPyObject_SetObj(self, py_call(&fn, args)); 
     119                return 0; 
     120            } else { 
     121                return findAndCallCtor!(current+1)(self, args, argCount); 
     122            } 
     123        } 
     124    } 
     125 
    81126    extern(C) 
    82127    int init_func(PyObject* self, PyObject* args, PyObject* kwds) { 
     
    91136                } 
    92137            } 
    93             // We only match the first supplied ctor with the proper number of 
    94             // arguments. (Eventually, we'll do some more sophisticated matching, 
    95             // but this will do for now.) 
    96             static if (ARGS >= 1) { 
    97                 if (len == TypeNo!(Tuple, 0).length) { 
    98                     // This works thusly: 
    99                     // 1) outer!(T).call_ctor is a series of template functions 
    100                     //    that call a constructor with its passed arguments, and 
    101                     //    return the new object. 
    102                     // 2) instant_from_tuple is a template that instantiates a 
    103                     //    template with the types in the passed tuple type. By 
    104                     //    combining call_ctor with the selected tuple representing 
    105                     //    the best match of constructor, we can get something like 
    106                     //    a pointer to a constructor function. 
    107                     // 3) This function pointer is sent off to py_call, which calls 
    108                     //    it with the PyTuple that args points to. 
    109                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 0) ) fn1; 
    110                     WrapPyObject_SetObj(self, py_call( &fn1, args )); 
    111                     return 0; 
    112                 } 
    113             } 
    114             static if (ARGS >= 2) { 
    115                 if (len == TypeNo!(Tuple, 1).length) { 
    116                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 1) ) fn2; 
    117                     WrapPyObject_SetObj(self, py_call( &fn2, args )); 
    118                     return 0; 
    119                 } 
    120             } 
    121             static if (ARGS >= 3) { 
    122                 if (len == TypeNo!(Tuple, 2).length) { 
    123                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 2) ) fn3; 
    124                     WrapPyObject_SetObj(self, py_call( &fn3, args )); 
    125                     return 0; 
    126                 } 
    127             } 
    128             static if (ARGS >= 4) { 
    129                 if (len == TypeNo!(Tuple, 3).length) { 
    130                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 3) ) fn4; 
    131                     WrapPyObject_SetObj(self, py_call( &fn4, args )); 
    132                     return 0; 
    133                 } 
    134             } 
    135             static if (ARGS >= 5) { 
    136                 if (len == TypeNo!(Tuple, 4).length) { 
    137                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 4) ) fn5; 
    138                     WrapPyObject_SetObj(self, py_call( &fn5, args )); 
    139                     return 0; 
    140                 } 
    141             } 
    142             static if (ARGS >= 6) { 
    143                 if (len == TypeNo!(Tuple, 5).length) { 
    144                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 5) ) fn6; 
    145                     WrapPyObject_SetObj(self, py_call( &fn6, args )); 
    146                     return 0; 
    147                 } 
    148             } 
    149             static if (ARGS >= 7) { 
    150                 if (len == TypeNo!(Tuple, 6).length) { 
    151                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 6) ) fn7; 
    152                     WrapPyObject_SetObj(self, py_call( &fn7, args )); 
    153                     return 0; 
    154                 } 
    155             } 
    156             static if (ARGS >= 8) { 
    157                 if (len == TypeNo!(Tuple, 7).length) { 
    158                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 7) ) fn8; 
    159                     WrapPyObject_SetObj(self, py_call( &fn8, args )); 
    160                     return 0; 
    161                 } 
    162             } 
    163             static if (ARGS >= 9) { 
    164                 if (len == TypeNo!(Tuple, 8).length) { 
    165                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 8) ) fn9; 
    166                     WrapPyObject_SetObj(self, py_call( &fn9, args )); 
    167                     return 0; 
    168                 } 
    169             } 
    170             static if (ARGS >= 10) { 
    171                 if (len == TypeNo!(Tuple, 9).length) { 
    172                     alias instant_from_tuple!( outer!(T).call_ctor, TypeNo!(Tuple, 9) ) fn10; 
    173                     WrapPyObject_SetObj(self, py_call( &fn10, args )); 
    174                     return 0; 
    175                 } 
    176             } else { 
    177                 PyErr_SetString(PyExc_TypeError, "Unsupported number of constructor arguments."); 
    178                 return -1; 
    179             } 
     138            return findAndCallCtor!(0) (self, args, len); 
    180139        }); 
    181140    } 
  • trunk/infrastructure/pyd/def.d

    r28 r40  
    2727private import pyd.dg_convert; 
    2828private import pyd.exception; 
    29 private import pyd.ftype; 
    3029private import pyd.func_wrap; 
    3130private import pyd.make_object; 
     31 
     32private import meta.Default; 
     33private import meta.Nameof; 
    3234 
    3335private import std.string; 
     
    7779 *It's greater than 10!) 
    7880 */ 
    79 template def(alias fn, char[] name, fn_t=typeof(&fn), uint MIN_ARGS = MIN_ARGS!(fn)) { 
     81template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) { 
    8082    pragma(msg, "def: " ~ name); 
    8183    void def() { 
  • trunk/infrastructure/pyd/dg_convert.d

    r25 r40  
    2828module pyd.dg_convert; 
    2929 
    30 private import pyd.ftype
     30private import meta.FuncMeta
    3131 
    3232template fn_to_dgT(Fn) { 
    33     const uint ARGS = NumberOfArgs!(Fn); 
    34     alias ReturnType!(Fn) RetType; 
     33    alias funcDelegInfoT!(Fn) Info; 
     34    const uint ARGS = Info.numArgs; 
     35    alias RetType!(Fn) Ret; 
     36 
     37    template A(uint i) { 
     38        alias Info.Meta.ArgType!(i) A; 
     39    } 
    3540 
    3641    static if (ARGS == 0) { 
    37         alias RetType delegate() type; 
     42        alias Ret delegate() type; 
    3843    } else static if (ARGS == 1) { 
    39         alias RetType delegate(ArgType!(Fn, 1)) type; 
     44        alias Ret delegate(A!(0)) type; 
    4045    } else static if (ARGS == 2) { 
    41         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2)) type; 
     46        alias Ret delegate(A!(0), A!(1)) type; 
    4247    } else static if (ARGS == 3) { 
    43         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3)) type; 
     48        alias Ret delegate(A!(0), A!(1), A!(2)) type; 
    4449    } else static if (ARGS == 4) { 
    45         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4)) type; 
     50        alias Ret delegate(A!(0), A!(1), A!(2), A!(3)) type; 
    4651    } else static if (ARGS == 5) { 
    47         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5)) type; 
     52        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4)) type; 
    4853    } else static if (ARGS == 6) { 
    49         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5), ArgType!(Fn, 6)) type; 
     54        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4), A!(5)) type; 
    5055    } else static if (ARGS == 7) { 
    51         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5), ArgType!(Fn, 6), ArgType!(Fn, 7)) type; 
     56        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4), A!(5), A!(6)) type; 
    5257    } else static if (ARGS == 8) { 
    53         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5), ArgType!(Fn, 6), ArgType!(Fn, 7), ArgType!(Fn, 8)) type; 
     58        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7)) type; 
    5459    } else static if (ARGS == 9) { 
    55         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5), ArgType!(Fn, 6), ArgType!(Fn, 7), ArgType!(Fn, 8), ArgType!(Fn, 9)) type; 
     60        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7), A!(8)) type; 
    5661    } else static if (ARGS == 10) { 
    57         alias RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3), ArgType!(Fn, 4), ArgType!(Fn, 5), ArgType!(Fn, 6), ArgType!(Fn, 7), ArgType!(Fn, 8), ArgType!(Fn, 9), ArgType!(Fn, 10)) type; 
     62        alias Ret delegate(A!(0), A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7), A!(8), A!(9)) type; 
    5863    } 
    5964} 
     
    8994    return u.real_dg; 
    9095} 
     96 
  • trunk/infrastructure/pyd/func_wrap.d

    r37 r40  
    2222module pyd.func_wrap; 
    2323 
    24 private import python; 
    25  
    26 private import pyd.class_wrap; 
    27 private import pyd.dg_convert; 
    28 private import pyd.exception; 
    29 private import pyd.ftype; 
    30 private import pyd.make_object; 
    31 private import pyd.tuples; 
    32  
    33 private import std.string; 
     24private { 
     25    import python; 
     26 
     27    import pyd.class_wrap; 
     28    import pyd.dg_convert; 
     29    import pyd.exception; 
     30    import pyd.make_object; 
     31 
     32    import meta.Tuple; 
     33    import meta.Bind; 
     34    import meta.FuncMeta; 
     35    import meta.Apply; 
     36    import meta.Default; 
     37    import meta.Nameof; 
     38 
     39    import std.string; 
     40
    3441 
    3542// Builds a Python callable object from a delegate or function pointer. 
    36 template DPyFunc_FromDG(T, uint MIN_ARGS=NumberOfArgs!(T)) { 
     43template DPyFunc_FromDG(T) { 
    3744    PyObject* DPyFunc_FromDG(T dg) { 
    3845        alias wrapped_class_type!(T) type; 
     
    5461} 
    5562 
     63// Populates the tuple t with converted arguments from the PyTuple args 
     64private void loop(T, uint i = 0) (T* t, PyObject* args) { 
     65    static if (i < T.length) { 
     66        t.val!(i) = d_type!(typeof(t.val!(i)))(PyTuple_GetItem(args, i)); 
     67        loop!(T, i+1)(t, args); 
     68    } 
     69} 
     70 
     71private void setWrongArgsError(int gotArgs, uint minArgs, uint maxArgs) { 
     72    char[] str = "Wrong number of arguments. Got " ~ 
     73        toString(gotArgs) ~ 
     74        ", expected "; 
     75    if (minArgs == maxArgs) str ~= toString(minArgs) ~ "."; 
     76    else str ~= "between " ~ toString(minArgs) ~ " and " ~ toString(maxArgs) ~ "."; 
     77    PyErr_SetString(PyExc_TypeError, str ~ \0); 
     78} 
     79 
    5680// Calls the passed function with the passed Python tuple. 
    57 ReturnType!(fn_t) py_call(fn_t, PY)(fn_t fn, PY* args) { 
    58     const uint MAX_ARGS = NumberOfArgs!(fn_t); 
    59     alias ReturnType!(fn_t) RetType; 
     81RetType!(fn_t) py_call(fn_t, PY)(fn_t fn, PY* args) { 
     82    alias funcDelegInfoT!(fn_t) Meta; 
     83    const uint MAX_ARGS = Meta.numArgs; 
     84    alias RetType!(fn_t) RT; 
    6085 
    6186    int ARGS = 0; 
     
    6388    if (args !is null) { 
    6489        ARGS = PyObject_Length(args); 
    65         assert(ARGS == MAX_ARGS, "Function called with wrong number of arguments"); 
     90        //assert(ARGS == MAX_ARGS, "Function called with wrong number of arguments"); 
    6691    } 
    6792 
    6893    // Sanity check! 
    6994    if (ARGS != MAX_ARGS) { 
    70         PyErr_SetString(PyExc_TypeError, 
    71             "Wrong number of arguments. Got " ~ 
    72             toString(ARGS) ~ 
    73             ", expected " ~ 
    74             toString(MAX_ARGS) ~ 
    75             " args."); 
     95        setWrongArgsError(ARGS, MAX_ARGS, MAX_ARGS); 
    7696        handle_exception(); 
    7797    } 
    7898 
    79     // I've refactored this to use a tuple rather than the old cascade of 
    80     // variable function calls. There are now 10 calls to d_type where there 
    81     // once were 110. 
    82     alias tuple_from_fn!(fn_t) t_t; // tuple type 
    83     t_t t; 
    84  
    85     static if (MAX_ARGS >= 1) 
    86         t.set!(0)(d_type!(t_t.TypeNo!(0))(PyTuple_GetItem(args, 0))); 
    87     static if (MAX_ARGS >= 2) 
    88         t.set!(1)(d_type!(t_t.TypeNo!(1))(PyTuple_GetItem(args, 1))); 
    89     static if (MAX_ARGS >= 3) 
    90         t.set!(2)(d_type!(t_t.TypeNo!(2))(PyTuple_GetItem(args, 2))); 
    91     static if (MAX_ARGS >= 4) 
    92         t.set!(3)(d_type!(t_t.TypeNo!(3))(PyTuple_GetItem(args, 3))); 
    93     static if (MAX_ARGS >= 5) 
    94         t.set!(4)(d_type!(t_t.TypeNo!(4))(PyTuple_GetItem(args, 4))); 
    95     static if (MAX_ARGS >= 6) 
    96         t.set!(5)(d_type!(t_t.TypeNo!(5))(PyTuple_GetItem(args, 5))); 
    97     static if (MAX_ARGS >= 7) 
    98         t.set!(6)(d_type!(t_t.TypeNo!(6))(PyTuple_GetItem(args, 6))); 
    99     static if (MAX_ARGS >= 8) 
    100         t.set!(7)(d_type!(t_t.TypeNo!(7))(PyTuple_GetItem(args, 7))); 
    101     static if (MAX_ARGS >= 9) 
    102         t.set!(8)(d_type!(t_t.TypeNo!(8))(PyTuple_GetItem(args, 8))); 
    103     static if (MAX_ARGS >= 10) 
    104         t.set!(9)(d_type!(t_t.TypeNo!(9))(PyTuple_GetItem(args, 9))); 
    105  
    106     static if (is(RetType : void)) { 
    107         apply_tuple_to_fn(t, fn); 
     99    alias getFuncTuple!(fn_t) T; // tuple type 
     100    T t; 
     101 
     102    loop!(T)(&t, args); 
     103 
     104    static if (is(RT : void)) { 
     105        apply(fn, t); 
    108106        return; 
    109107    } else { 
    110         return apply_tuple_to_fn(t, fn); 
     108        return apply(fn, t); 
    111109    } 
    112110} 
    113111 
    114112template wrapped_func_call(fn_t) { 
    115     const uint MAX_ARGS = NumberOfArgs!(fn_t); 
    116     alias ReturnType!(fn_t) RetType; 
     113    alias funcDelegInfoT!(fn_t) Meta; 
     114    const uint MAX_ARGS = Meta.numArgs; 
     115    alias RetType!(fn_t) RT; 
    117116    // The entry for the tp_call slot of the DPyFunc types. 
    118117    // (Or: What gets called when you pass a delegate or function pointer to 
     
    129128 
    130129        return exception_catcher({ 
    131             static if (is(RetType == void)) { 
     130            static if (is(RT == void)) { 
    132131                py_call(fn, args); 
    133132                Py_INCREF(Py_None); 
     
    143142// with a PyCFunction. 
    144143template func_wrap(alias real_fn, uint MIN_ARGS, C=void, fn_t=typeof(&real_fn)) { 
    145     const uint MAX_ARGS = NumberOfArgs!(fn_t); 
    146     alias ReturnType!(fn_t) RetType; 
     144    alias funcDelegInfoT!(fn_t) Meta; 
     145    const uint MAX_ARGS = Meta.numArgs; 
     146    alias RetType!(fn_t) RT; 
    147147 
    148148    // Wraps py_call to return a PyObject* 
    149149    PyObject* py_py_call(fn_t, PY)(fn_t fn, PY* args) { 
    150         static if (is(ReturnType!(fn_t) == void)) { 
     150        static if (is(RetType!(fn_t) == void)) { 
    151151            py_call(fn, args); 
    152152            Py_INCREF(Py_None); 
     
    157157    } 
    158158 
     159    // Loops through the tuple of function pointers until the number of 
     160    // elements in the PyTuple equals the number of arguments accepted by the 
     161    // function pointer. Then, it applies the PyTuple to the function pointer. 
     162    PyObject* loop(T, uint i = 0) (T* t, PyObject* args, int argCount) { 
     163        static if (i == T.length) { 
     164            // This is tripped if the number of args in the passed PyTuple is 
     165            // not matched to a function pointer in the defaultsTuple. 
     166            setWrongArgsError(argCount, MIN_ARGS, MAX_ARGS); 
     167            return null; 
     168        } else { 
     169            alias funcDelegInfoT!(typeof(t.val!(i))) current; 
     170            if (current.numArgs == argCount) { 
     171                return py_py_call(t.val!(i), args); 
     172            } 
     173            return loop!(T, i+1) (t, args, argCount); 
     174        } 
     175    } 
     176 
    159177    // Calls py_py_call with the proper function contained in a tuple 
    160178    // returned from tuples.func_range. 
    161179    PyObject* tuple_py_call(Tu, PY)(Tu t, PY* args) { 
    162         int ARGS = 0; 
     180        int argCount = 0; 
    163181        if (args !is null) 
    164             ARGS = PyObject_Length(args); 
     182            argCount = PyObject_Length(args); 
     183         
    165184        static if (MIN_ARGS == 0) { 
    166             if (ARGS == 0) 
    167                 return py_py_call(&partial!(real_fn, 0), args); 
    168         } static if (!is(TypeNo!(Tu, 0) == Void)) { 
    169             if (ARGS == 1) 
    170                 return py_py_call(t.get!(0), args); 
    171         } static if (!is(TypeNo!(Tu, 1) == Void)) { 
    172             if (ARGS == 2) 
    173                 return py_py_call(t.get!(1), args); 
    174         } static if (!is(TypeNo!(Tu, 2) == Void)) { 
    175             if (ARGS == 3) 
    176                 return py_py_call(t.get!(2), args); 
    177         } static if (!is(TypeNo!(Tu, 3) == Void)) { 
    178             if (ARGS == 4) 
    179                 return py_py_call(t.get!(3), args); 
    180         } static if (!is(TypeNo!(Tu, 4) == Void)) { 
    181             if (ARGS == 5) 
    182                 return py_py_call(t.get!(4), args); 
    183         } static if (!is(TypeNo!(Tu, 5) == Void)) { 
    184             if (ARGS == 6) 
    185                 return py_py_call(t.get!(5), args); 
    186         } static if (!is(TypeNo!(Tu, 6) == Void)) { 
    187             if (ARGS == 7) 
    188                 return py_py_call(t.get!(6), args); 
    189         } static if (!is(TypeNo!(Tu, 7) == Void)) { 
    190             if (ARGS == 8) 
    191                 return py_py_call(t.get!(7), args); 
    192         } static if (!is(TypeNo!(Tu, 8) == Void)) { 
    193             if (ARGS == 9) 
    194                 return py_py_call(t.get!(8), args); 
    195         } static if (!is(TypeNo!(Tu, 9) == Void)) { 
    196             if (ARGS == 10) 
    197                 return py_py_call(t.get!(9), args); 
    198         } 
    199         PyErr_SetString(PyExc_RuntimeError, "Something happened..."); 
    200         return null; 
     185            if (argCount == 0) 
     186                return py_py_call(&firstArgs!(real_fn, 0, fn_t), args); 
     187        } 
     188        return loop!(Tu)(&t, args, argCount); 
    201189    } 
    202190 
     
    207195        return exception_catcher(delegate PyObject*() { 
    208196            // If C is specified, then this is a method call. We need to pull out 
    209             // the object in self and turn the member function pointer in real_fn 
     197            // the object in self and turn the member function alias real_fn 
    210198            // into a delegate. This conversion is done with a dirty hack; see 
    211199            // dg_convert.d. 
     
    219207                C instance = (cast(wrapped_class_object!(C)*)self).d_obj; 
    220208                fn_to_dg!(fn_t) fn = dg_wrapper!(C, fn_t)(instance, &real_fn); 
    221                 static if (is(ReturnType!(typeof(fn)) == void)) { 
     209                static if (is(RetType!(typeof(fn)) == void)) { 
    222210                    py_call(fn, args); 
    223211                    Py_INCREF(Py_None); 
     
    228216            // If C is not specified, then this is just a normal function call. 
    229217            } else { 
    230                 return tuple_py_call(func_range!(real_fn, MIN_ARGS)(), args); 
     218                return tuple_py_call(defaultsTuple!(real_fn, MIN_ARGS, fn_t)(), args); 
    231219            } 
    232220        }); 
     
    252240 
    253241Dg DPyCallable_AsDelegate(Dg) (PyObject* c) { 
    254     auto f = new DPyWrappedFunc(c); 
    255  
    256     const uint ARGS = NumberOfArgs!(Dg); 
    257     alias ReturnType!(Dg) Tr; 
    258     static if (ARGS == 0) 
    259         return &f.fn!(Tr); 
    260     else static if (ARGS == 1) 
    261         return &f.fn!(Tr, ArgType!(Dg, 1)); 
    262     else static if (ARGS == 2) 
    263         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2)); 
    264     else static if (ARGS == 3) 
    265         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3)); 
    266     else static if (ARGS == 4) 
    267         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4)); 
    268     else static if (ARGS == 5) 
    269         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5)); 
    270     else static if (ARGS == 6) 
    271         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6)); 
    272     else static if (ARGS == 7) 
    273         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7)); 
    274     else static if (ARGS == 8) 
    275         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8)); 
    276     else static if (ARGS == 9) 
    277         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8), ArgType!(Dg, 9)); 
    278     else static if (ARGS == 10) 
    279         return &f.fn!(Tr, ArgType!(Dg, 1), ArgType!(Dg, 2), ArgType!(Dg, 3), ArgType!(Dg, 4), ArgType!(Dg, 5), ArgType!(Dg, 6), ArgType!(Dg, 7), ArgType!(Dg, 8), ArgType!(Dg, 9), ArgType!(Dg, 10)); 
    280     else static assert(false, "Unsupported number of args in delegate type."); 
    281 
    282  
    283 class Dummy { } 
     242    return _pycallable_asdgT!(Dg).func(c); 
     243
     244 
     245private template _pycallable_asdgT(Dg) { 
     246    alias funcDelegInfoT!(Dg) Info; 
     247    const uint ARGS = Info.numArgs; 
     248    alias RetType!(Dg) Tr; 
     249 
     250    template A(uint i) { 
     251        alias Info.Meta.ArgType!(i-1) A; 
     252    } 
     253 
     254    Dg func(PyObject* c) { 
     255        auto f = new DPyWrappedFunc(c); 
     256 
     257        static if (ARGS == 0) 
     258            return &f.fn!(Tr); 
     259        else static if (ARGS == 1) 
     260            return &f.fn!(Tr, A!(1)); 
     261        else static if (ARGS == 2) 
     262            return &f.fn!(Tr, A!(1), A!(2)); 
     263        else static if (ARGS == 3) 
     264            return &f.fn!(Tr, A!(1), A!(2), A!(3)); 
     265        else static if (ARGS == 4) 
     266            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4)); 
     267        else static if (ARGS == 5) 
     268            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5)); 
     269        else static if (ARGS == 6) 
     270            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5), A!(6)); 
     271        else static if (ARGS == 7) 
     272            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7)); 
     273        else static if (ARGS == 8) 
     274            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7), A!(8)); 
     275        else static if (ARGS == 9) 
     276            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7), A!(8), A!(9)); 
     277        else static if (ARGS == 10) 
     278            return &f.fn!(Tr, A!(1), A!(2), A!(3), A!(4), A!(5), A!(6), A!(7), A!(8), A!(9), A!(10)); 
     279        else static assert(false, "Unsupported number of args in delegate type."); 
     280    } 
     281
    284282 
    285283private 
     
    297295     
    298296    Tr fn(Tr)() { 
    299         return boilerplate!(Tr)(call()); 
     297        return boilerplate!(Tr)(call(makeTuple())); 
    300298    } 
    301299     
    302300    Tr fn(Tr, T1)(T1 t1) { 
    303         return boilerplate!(Tr)(call(t1)); 
     301        return boilerplate!(Tr)(call(makeTuple(t1))); 
    304302    } 
    305303 
    306304    Tr fn(Tr, T1, T2)(T1 t1, T2 t2) { 
    307         return boilerplate!(Tr)(call(t1, t2)); 
     305        return boilerplate!(Tr)(call(makeTuple(t1, t2))); 
    308306    } 
    309307 
    310308    Tr fn(Tr, T1, T2, T3)(T1 t1, T2 t2, T3 t3) { 
    311         return boilerplate!(Tr)(call(t1, t2, t3)); 
     309        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3))); 
    312310    } 
    313311 
    314312    Tr fn(Tr, T1, T2, T3, T4)(T1 t1, T2 t2, T3 t3, T4 t4) { 
    315         return boilerplate!(Tr)(call(t1, t2, t3, t4)); 
     313        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4))); 
    316314    } 
    317315 
    318316    Tr fn(Tr, T1, T2, T3, T4, T5)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) { 
    319         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5)); 
     317        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5))); 
    320318    } 
    321319 
    322320    Tr fn(Tr, T1, T2, T3, T4, T5, T6)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) { 
    323         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6)); 
     321        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5, t6))); 
    324322    } 
    325323 
    326324    Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) { 
    327         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7)); 
     325        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5, t6, t7))); 
    328326    } 
    329327 
    330328    Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) { 
    331         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8)); 
     329        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5, t6, t7, t8))); 
    332330    } 
    333331 
    334332    Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8, T9)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) { 
    335         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8, t9)); 
     333        return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5, t6, t7, t8, t9))); 
    336334    } 
    337335 
    338336    Tr fn(Tr, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10) { 
    339         return boilerplate!(Tr)(call(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); 
    340     } 
    341      
    342     template call(T1=Dummy, T2=Dummy, T3=Dummy, T4=Dummy, T5=Dummy, T6=Dummy, T7=Dummy, T8=Dummy, T9=Dummy, T10=Dummy) { 
    343         PyObject* call (T1 t1=null, T2 t2=null, T3 t3=null, T4 t4=null, T5 t5=null, T6 t6=null, T7 t7=null, T8 t8=null, T9 t9=null, T10 t10=null) { 
    344             static if (!is(T10 == Dummy)) 
    345                 const uint ARGS = 10; 
    346             else static if (!is(T9 == Dummy)) 
    347                 const uint ARGS = 9; 
    348             else static if (!is(T8 == Dummy)) 
    349                 const uint ARGS = 8; 
    350             else static if (!is(T7 == Dummy)) 
    351                 const uint ARGS = 7; 
    352             else static if (!is(T6 == Dummy)) 
    353                 const uint ARGS = 6; 
    354             else static if (!is(T5 == Dummy)) 
    355                 const uint ARGS = 5; 
    356