Changeset 50

Show
Ignore:
Timestamp:
12/02/06 20:07:54 (2 years ago)
Author:
KirkMcDonald
Message:

func_wrap reorganization, and small make_object fix

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/infrastructure/pyd/class_wrap.d

    r49 r50  
    214214    extern(C) 
    215215    PyObject* func(PyObject* self, void* closure) { 
    216         // func_wrap already catches exceptions 
    217         return func_wrap!(Fn, 0, T, property_parts!(Fn).getter_type).func(self, null); 
     216        // method_wrap already catches exceptions 
     217        return method_wrap!(T, Fn, property_parts!(Fn).getter_type).func(self, null); 
    218218    } 
    219219} 
     
    229229        Py_INCREF(value); 
    230230        PyTuple_SetItem(temp_tuple, 0, value); 
    231         PyObject* res = func_wrap!(Fn, 1, T, property_parts!(Fn).setter_type).func(self, temp_tuple); 
     231        PyObject* res = method_wrap!(T, Fn, property_parts!(Fn).setter_type).func(self, temp_tuple); 
    232232        // If we get something back, we need to DECREF it. 
    233233        if (res) Py_DECREF(res); 
     
    262262         *        if more than one function has the same name as this one. 
    263263         */ 
    264         template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) { 
     264        template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) { 
    265265            pragma(msg, "class.def: " ~ name); 
    266266            static void def() { 
     
    268268                alias wrapped_method_list!(T) list; 
    269269                list[length-1].ml_name = name ~ \0; 
    270                 list[length-1].ml_meth = &func_wrap!(fn, MIN_ARGS, T, fn_t).func; 
     270                list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 
    271271                list[length-1].ml_flags = METH_VARARGS; 
    272272                list[length-1].ml_doc = ""; 
     
    413413    // opCall 
    414414    static if (is(typeof(&T.opCall))) { 
    415         type.tp_call = cast(ternaryfunc)&func_wrap!(T.opCall, minArgs!(T.opCall), T).func; 
     415        type.tp_call = cast(ternaryfunc)&method_wrap!(T, T.opCall, typeof(&T.opCall)).func; 
    416416    } 
    417417 
  • trunk/infrastructure/pyd/ctor_wrap.d

    r45 r50  
    6969                alias ParameterTypeTuple!(typeof(arg)) Ctor; 
    7070                if (Ctor.length == len) { 
    71                     alias call_ctor!(T, ParameterTypeTuple!(typeof(arg))) fn; 
    72                     WrapPyObject_SetObj(self, py_call(&fn, args)); 
     71                    auto fn = &call_ctor!(T, ParameterTypeTuple!(typeof(arg))); 
     72                    if (fn is null) { 
     73                        PyErr_SetString(PyExc_RuntimeError, "Couldn't get pointer to class ctor redirect."); 
     74                        return -1; 
     75                    } 
     76                    T t = applyPyTupleToDelegate(fn, args); 
     77                    if (t is null) { 
     78                        PyErr_SetString(PyExc_RuntimeError, "Class ctor redirect didn't return a class instance!"); 
     79                        return -1; 
     80                    } 
     81                    WrapPyObject_SetObj(self, t); 
    7382                    return 0; 
    7483                } 
  • trunk/infrastructure/pyd/def.d

    r49 r50  
    8080 
    8181        list[length-1].ml_name = name ~ \0; 
    82         list[length-1].ml_meth = &func_wrap!(fn, MIN_ARGS, void, fn_t).func; 
     82        list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; 
    8383        list[length-1].ml_flags = METH_VARARGS; 
    8484        list[length-1].ml_doc = ""; 
  • trunk/infrastructure/pyd/func_wrap.d

    r49 r50  
    3535    import std.string; 
    3636    import std.traits; 
    37 
    38  
    39 // Builds a Python callable object from a delegate or function pointer. 
     37    import std.stdio; 
     38
     39 
     40// Builds a callable Python object from a delegate or function pointer. 
    4041PyObject* PydFunc_FromDelegate(T) (T dg) { 
    4142    alias wrapped_class_type!(T) type; 
     
    9192} 
    9293 
    93 // Calls the passed function with the passed Python tuple
    94 ReturnType!(fn_t) py_call(fn_t, PY)(fn_t fn, PY* args) { 
     94// Calls callable alias fn with PyTuple args
     95ReturnType!(fn_t) applyPyTupleToAlias(alias fn, fn_t, uint MIN_ARGS) (PyObject* args) { 
    9596    alias ParameterTypeTuple!(fn_t) T; 
    9697    const uint MAX_ARGS = T.length; 
    9798    alias ReturnType!(fn_t) RT; 
    9899 
    99     int ARGS = 0; 
     100    int argCount = 0; 
    100101    // This can make it more convenient to call this with 0 args. 
    101102    if (args !is null) { 
    102         ARGS = PyObject_Length(args); 
     103        argCount = PyObject_Length(args); 
    103104    } 
    104105 
    105106    // Sanity check! 
    106     if (ARGS != MAX_ARGS) { 
    107         setWrongArgsError(ARGS, MAX_ARGS, MAX_ARGS); 
     107    if (argCount < MIN_ARGS || argCount > MAX_ARGS) { 
     108        setWrongArgsError(argCount, MIN_ARGS, MAX_ARGS); 
    108109        handle_exception(); 
    109110    } 
    110111 
     112    static if (MIN_ARGS == 0) { 
     113        if (argCount == 0) { 
     114            return fn(); 
     115        } 
     116    } 
     117    T t; 
     118    foreach(i, arg; t) { 
     119        const uint argNum = i+1; 
     120        if (i < argCount) { 
     121            t[i] = d_type!(typeof(arg))(PyTuple_GetItem(args, i)); 
     122        } 
     123        static if (argNum >= MIN_ARGS && argNum <= MAX_ARGS) { 
     124            if (argNum == argCount) { 
     125                return fn(t[0 .. argNum]); 
     126                break; 
     127            } 
     128        } 
     129    } 
     130    // This should never get here. 
     131    throw new Exception("applyPyTupleToAlias reached end! argCount = " ~ toString(argCount)); 
     132    static if (!is(RT == void)) 
     133        return ReturnType!(fn_t).init; 
     134} 
     135 
     136// wraps applyPyTupleToAlias to return a PyObject* 
     137PyObject* pyApplyToAlias(alias fn, fn_t, uint MIN_ARGS) (PyObject* args) { 
     138    static if (is(ReturnType!(fn_t) == void)) { 
     139        applyPyTupleToAlias!(fn, fn_t, MIN_ARGS)(args); 
     140        Py_INCREF(Py_None); 
     141        return Py_None; 
     142    } else { 
     143        return _py( applyPyTupleToAlias!(fn, fn_t, MIN_ARGS)(args) ); 
     144    } 
     145} 
     146 
     147ReturnType!(dg_t) applyPyTupleToDelegate(dg_t) (dg_t dg, PyObject* args) { 
     148    alias ParameterTypeTuple!(dg_t) T; 
     149    const uint ARGS = T.length; 
     150    alias ReturnType!(dg_t) RT; 
     151 
     152    int argCount = 0; 
     153    // This can make it more convenient to call this with 0 args. 
     154    if (args !is null) { 
     155        argCount = PyObject_Length(args); 
     156    } 
     157 
     158    // Sanity check! 
     159    if (argCount != ARGS) { 
     160        setWrongArgsError(argCount, ARGS, ARGS); 
     161        handle_exception(); 
     162    } 
     163 
     164    static if (ARGS == 0) { 
     165        if (argCount == 0) { 
     166            return dg(); 
     167        } 
     168    } 
    111169    T t; 
    112170    foreach(i, arg; t) { 
    113171        t[i] = d_type!(typeof(arg))(PyTuple_GetItem(args, i)); 
    114172    } 
    115  
    116     static if (is(RT == void)) { 
    117         fn(t); 
    118         return; 
     173    return dg(t); 
     174
     175 
     176// wraps applyPyTupleToDelegate to return a PyObject* 
     177PyObject* pyApplyToDelegate(dg_t) (dg_t dg, PyObject* args) { 
     178    static if (is(ReturnType!(dg_t) == void)) { 
     179        applyPyTupleToDelegate(dg, args); 
     180        Py_INCREF(Py_None); 
     181        return Py_None; 
    119182    } else { 
    120         return fn(t); 
     183        return _py( applyPyTupleToDelegate(dg, args) ); 
    121184    } 
    122185} 
    123186 
    124187template wrapped_func_call(fn_t) { 
     188    const uint ARGS = ParameterTypeTuple!(fn_t).length; 
    125189    alias ReturnType!(fn_t) RT; 
    126190    // The entry for the tp_call slot of the PydFunc types. 
     
    137201 
    138202        return exception_catcher({ 
    139             static if (is(RT == void)) { 
    140                 py_call(fn, args); 
    141                 Py_INCREF(Py_None); 
    142                 return Py_None; 
    143             } else { 
    144                 return _py( py_call(fn, args) ); 
    145             } 
     203            return pyApplyToDelegate(fn, args); 
    146204        }); 
    147205    } 
    148206} 
    149207 
    150 // This is a handy shortcut that allows us to wrap a function alias directly 
    151 // with a PyCFunction. 
    152 template func_wrap(alias real_fn, uint MIN_ARGS, C=void, fn_t=typeof(&real_fn)) { 
     208// Wraps a function alias with a PyCFunction. 
     209template function_wrap(alias real_fn, uint MIN_ARGS, fn_t=typeof(&real_fn)) { 
    153210    alias ParameterTypeTuple!(fn_t) Info; 
    154211    const uint MAX_ARGS = Info.length; 
    155212    alias ReturnType!(fn_t) RT; 
    156213 
    157     // Wraps py_call to return a PyObject* 
    158     PyObject* py_py_call(fn_t, PY)(fn_t fn, PY* args) { 
    159         static if (is(RT == void)) { 
    160             py_call(fn, args); 
    161             Py_INCREF(Py_None); 
    162             return Py_None; 
    163         } else { 
    164             return _py( py_call(fn, args) ); 
    165         } 
    166     } 
    167  
    168     // Calls py_py_call with the proper function contained in a tuple 
    169     // returned from tuples.func_range. 
    170     PyObject* tuple_py_call(PY, T ...)(PY* args, T t) { 
    171         int argCount = 0; 
    172         if (args !is null) 
    173             argCount = PyObject_Length(args); 
    174          
    175         static if (MIN_ARGS == 0) { 
    176             if (argCount == 0) 
    177                 return py_py_call(&firstArgs!(real_fn, 0, fn_t), args); 
    178         } 
    179         foreach (i, arg; t) { 
    180             if (ParameterTypeTuple!(typeof(arg)).length == argCount) { 
    181                 return py_py_call(arg, args); 
    182             } 
    183         } 
    184     } 
    185  
    186214    extern (C) 
    187215    PyObject* func(PyObject* self, PyObject* args) { 
    188         // For some reason, D can't infer the return type of this function 
    189         // literal... 
    190216        return exception_catcher(delegate PyObject*() { 
    191             // If C is specified, then this is a method call. We need to pull out 
    192             // the object in self and turn the member function alias real_fn 
    193             // into a delegate. This conversion is done with a dirty hack; see 
    194             // dg_convert.d. 
    195             static if (!is(C == void)) { 
    196                 static assert (MIN_ARGS == MAX_ARGS, "Default arguments with member functions are not supported."); 
    197                 // Didn't pass a "self" parameter! Ack! 
    198                 if (self is null) { 
    199                     PyErr_SetString(PyExc_TypeError, "Wrapped method didn't get a 'self' parameter."); 
    200                     return null; 
    201                 } 
    202                 C instance = (cast(wrapped_class_object!(C)*)self).d_obj; 
    203                 fn_to_dg!(fn_t) fn = dg_wrapper!(C, fn_t)(instance, &real_fn); 
    204                 static if (is(ReturnType!(typeof(fn)) == void)) { 
    205                     py_call(fn, args); 
    206                     Py_INCREF(Py_None); 
    207                     return Py_None; 
    208                 } else { 
    209                     return _py( py_call(fn, args) ); 
    210                 } 
    211             // If C is not specified, then this is just a normal function call. 
    212             } else { 
    213                 alias defaultsTupleT!(real_fn, MIN_ARGS, fn_t).type T; 
    214                 T t; 
    215                 defaultsTuple!(real_fn, MIN_ARGS, fn_t)(delegate void(T tu) { 
    216                     foreach(i, arg; tu) { 
    217                         t[i] = arg; 
    218                     } 
    219                 }); 
    220                 return tuple_py_call(args, t); 
     217            return pyApplyToAlias!(real_fn, fn_t, MIN_ARGS)(args); 
     218        }); 
     219    } 
     220
     221 
     222// Wraps a member function alias with a PyCFunction. 
     223template method_wrap(C, alias real_fn, fn_t=typeof(&real_fn)) { 
     224    alias ParameterTypeTuple!(fn_t) Info; 
     225    const uint ARGS = Info.length; 
     226    alias ReturnType!(fn_t) RT; 
     227    extern(C) 
     228    PyObject* func(PyObject* self, PyObject* args) { 
     229        return exception_catcher(delegate PyObject*() { 
     230            // Didn't pass a "self" parameter! Ack! 
     231            if (self is null) { 
     232                PyErr_SetString(PyExc_TypeError, "Wrapped method didn't get a 'self' parameter."); 
     233                return null; 
    221234            } 
     235            C instance = (cast(wrapped_class_object!(C)*)self).d_obj; 
     236            if (instance is null) { 
     237                PyErr_SetString(PyExc_ValueError, "Wrapped class instance is null!"); 
     238                return null; 
     239            } 
     240            fn_to_dg!(fn_t) dg = dg_wrapper!(C, fn_t)(instance, &real_fn); 
     241            return pyApplyToDelegate(dg, args); 
    222242        }); 
    223243    } 
  • trunk/infrastructure/pyd/make_object.d

    r49 r50  
    144144        } 
    145145        // If it's not a wrapped type, fall through to the exception. 
    146     // This just passes the argument right back through without changing 
    147     // its reference count. 
     146    // The function expects to be passed a borrowed reference and return an 
     147    // owned reference. Thus, if passed a PyObject*, this will increment the 
     148    // reference count. 
    148149    } else static if (is(T : PyObject*)) { 
     150        Py_INCREF(t); 
    149151        return t; 
    150152    } 
     
    178180 * Calling this with a PydObject will return back a reference to the very same 
    179181 * PydObject. 
    180  * 
    181  * Calling this with a PyObject* will "steal" the reference. 
    182182 */ 
    183183PydObject py(T) (T t) { 
  • trunk/infrastructure/pyd/op_wrap.d

    r47 r50  
    147147    extern(C) 
    148148    PyObject* func(PyObject* self) { 
    149         // func_wrap takes care of exception handling 
    150         return func_wrap!(opfn, 0, T).func(self, null); 
     149        // method_wrap takes care of exception handling 
     150        return method_wrap!(T, opfn, typeof(&opfn)).func(self, null); 
    151151    } 
    152152} 
     
    205205                return null; 
    206206            } 
    207             return func_wrap!(T.opIndex, ARGS, T).func(self, key); 
     207            return method_wrap!(T, T.opIndex, typeof(&T.opIndex)).func(self, key); 
    208208        } 
    209209    } 
     
    237237                PyTuple_SetItem(temp, i, PyTuple_GetItem(key, i-1)); 
    238238            } 
    239             func_wrap!(T.opIndexAssign, ARGS, T).func(self, temp); 
     239            method_wrap!(T, T.opIndexAssign, typeof(&T.opIndexAssign)).func(self, temp); 
    240240            return 0; 
    241241        }