Changeset 101

Show
Ignore:
Timestamp:
02/21/07 17:01:34 (1 year ago)
Author:
KirkMcDonald
Message:

The purpose of shim classes is now somewhat more well-defined. (The same Python class now wraps both the original D class and its shim.) This fixes a couple of bugs, and makes wrap_class somewhat easier to understand.

Files:

Legend:

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

    r100 r101  
    285285    static const uint min_args = MIN_ARGS; 
    286286 
    287     static void call(T) () { 
     287    static void call(T, shim) () { 
    288288        pragma(msg, "class.def: " ~ name); 
    289289        static PyMethodDef empty = { null, null, 0, null }; 
     
    305305            "    }\n"; 
    306306    } 
    307     template shim_call(char[] varname, uint i) { 
    308         const char[] shim_call = "Def!("~varname~"."~_realname~", p"~ToString!(i)~".realname, p"~ToString!(i)~".funcname, p"~ToString!(i)~".func_t, p"~ToString!(i)~".min_args)"; 
    309     } 
    310307} 
    311308 
     
    319316    static const char[] funcname = name; 
    320317    static const uint min_args = MIN_ARGS; 
    321     static void call(T) () { 
     318    static void call(T, shim) () { 
    322319        pragma(msg, "class.static_def: " ~ name); 
    323320        static PyMethodDef empty = { null, null, 0, null }; 
     
    333330        const char[] shim = ""; 
    334331    } 
    335     template shim_call(char[] varname, uint i) { 
    336         const char[] shim_call = "DoNothing"; 
    337     } 
    338332} 
    339333 
     
    355349    static const char[] funcname = name; 
    356350    static const bool readonly = RO; 
    357     static void call(T) () { 
     351    static void call(T, shim) () { 
    358352        pragma(msg, "class.prop: " ~ name); 
    359353        static PyGetSetDef empty = { null, null, null, null, null }; 
     
    391385            shim_setter!(i); 
    392386    } 
    393     template shim_call(char[] varname, uint i) { 
    394         const char[] shim_call = "Property!("~varname~"."~_realname~", p"~ToString!(i)~".realname, p"~ToString!(i)~".funcname, p"~ToString!(i)~".readonly)"; 
    395     } 
    396387} 
    397388 
     
    410401struct Init(C ...) { 
    411402    alias C ctors; 
    412     static void call(T) () { 
     403    static void call(T, shim) () { 
    413404        wrapped_class_type!(T).tp_init = 
    414             &wrapped_ctors!(T, C).init_func; 
     405            &wrapped_ctors!(shim, C).init_func; 
    415406    } 
    416407    template shim_impl(uint i, uint c=0) { 
     
    421412                "    }\n" ~ shim_impl!(i, c+1); 
    422413        } else { 
    423             const char[] shim_impl = ""; 
     414            const char[] shim_impl = 
     415                "    static if (is(typeof(new T))) {\n" 
     416                "        this() { super(); }\n" 
     417                "    }\n"; 
    424418        } 
    425419    } 
     
    430424            shim_impl!(i); 
    431425    } 
    432     template shim_call(char[] varname, uint i) { 
    433         const char[] shim_call = "Init!(p"~ToString!(i)~".ctors)"; 
    434     } 
    435426} 
    436427 
     
    444435*/ 
    445436struct Iter(iter_t) { 
    446     static void call(T) () { 
     437    alias iter_t iterator_t; 
     438    static void call(T, shim) () { 
    447439        PydStackContext_Ready(); 
    448440        // This strange bit of hackery is needed since we operate on pointer- 
     
    462454*/ 
    463455struct AltIter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) { 
    464     static void call(T) () { 
     456    static void call(T, shim) () { 
    465457        static PyMethodDef empty = { null, null, 0, null }; 
    466458        alias wrapped_method_list!(T) list; 
     
    479471} /*Pyd_with_StackThreads*/ 
    480472 
    481 private 
    482 template comma(uint i, uint length) { 
    483     static if (i < length-1) { 
    484         const char[] comma = ","; 
    485     } else { 
    486         const char[] comma = ""; 
    487     } 
    488 } 
    489  
    490 private 
    491 template recursive_call(char[] name, int i, Params...) { 
    492     static if (i < Params.length) { 
    493         const char[] recursive_call = Params[i].shim_call!(name, i) ~ comma!(i, Params.length) ~ recursive_call!(name, i+1, Params); 
    494     } else { 
    495         const char[] recursive_call = ""; 
    496     } 
    497 } 
    498  
    499 private 
    500 template aliases(uint i, Params...) { 
    501     static if (i < Params.length) { 
    502         const char[] aliases = "alias Params["~ToString!(i)~"] p"~ToString!(i)~";\n" ~ aliases!(i+1, Params); 
    503     } else { 
    504         const char[] aliases = ""; 
    505     } 
    506 } 
    507  
    508473void wrap_class(T, Params...) (char[] docstring="", char[] modulename="") { 
    509     wrap_class!(void, T, symbolnameof!(T), Params)(docstring, modulename); 
    510 
    511 void wrap_class(T, char[] name, Params...) (char[] docstring="", char[] modulename="") { 
    512     wrap_class!(void, T, name, Params)(docstring, modulename); 
    513 
    514  
    515 void wrap_class(wrapping, _T, char[] name, Params...) (char[] docstring="", char[] modulename="") { 
     474    wrap_class!(T, symbolnameof!(T), Params)(docstring, modulename); 
     475
     476void wrap_class(_T, char[] name, Params...) (char[] docstring="", char[] modulename="") { 
    516477    //alias CLS.wrapped_type T; 
    517478    //const char[] name = CLS._name; 
    518479    static if (is(_T == class)) { 
    519480        pragma(msg, "wrap_class: " ~ name); 
     481        alias make_wrapper!(_T, Params).wrapper shim_class; 
    520482        alias _T T; 
    521483    } else { 
    522484        pragma(msg, "wrap_struct: " ~ name); 
     485        alias void shim_class; 
    523486        alias _T* T; 
    524487    } 
     
    528491    //Params params; 
    529492    foreach (param; Params) { 
    530         param.call!(T)(); 
     493        param.call!(T, shim_class)(); 
    531494    } 
    532495 
     
    548511    // Inheritance // 
    549512    ///////////////// 
    550     static if (is(wrapping == void)) { 
    551         // Inherit directly-wrapped classes from their wrapped superclass. 
    552         static if (is(T B == super)) { 
    553             foreach (C; B) { 
    554                 static if (is(C == class) && !is(C == Object)) { 
    555                     if (is_wrapped!(C)) { 
    556                         type.tp_base = &wrapped_class_type!(C); 
    557                     } 
    558                 } 
    559             } 
    560         } 
    561     } else { 
    562         // Inherit shims from their grandparent's shim. 
    563         static if (is(wrapping B == super)) { 
    564             foreach (C; B) { 
    565                 static if (is(C == class) && !is(C == Object)) { 
    566                     type.tp_base = shim_class!(C); 
     513    // Inherit classes from their wrapped superclass. 
     514    static if (is(T B == super)) { 
     515        foreach (C; B) { 
     516            static if (is(C == class) && !is(C == Object)) { 
     517                if (is_wrapped!(C)) { 
     518                    type.tp_base = &wrapped_class_type!(C); 
    567519                } 
    568520            } 
     
    608560    // Constructor wrapping // 
    609561    ////////////////////////// 
    610     static if (is(wrapping == void) && is(T == class)) { 
    611         // Non-shim classes cannot be instantiated from Python. 
    612         type.tp_init = null; 
    613     } else { 
    614         // If a ctor wasn't supplied, try the default. 
    615         // If the default ctor isn't available, and no ctors were supplied, 
    616         // then this class cannot be instantiated from Python. 
    617         // (Structs always use the default ctor.) 
    618         static if (is(typeof(new T))) { 
    619             if (type.tp_init is null) { 
    620                 static if (is(T == class)) { 
    621                     type.tp_init = &wrapped_init!(T).init; 
    622                 } else { 
    623                     type.tp_init = &wrapped_struct_init!(T).init; 
    624                 } 
     562    // If a ctor wasn't supplied, try the default. 
     563    // If the default ctor isn't available, and no ctors were supplied, 
     564    // then this class cannot be instantiated from Python. 
     565    // (Structs always use the default ctor.) 
     566    static if (is(typeof(new T))) { 
     567        if (type.tp_init is null) { 
     568            static if (is(T == class)) { 
     569                type.tp_init = &wrapped_init!(shim_class).init; 
     570            } else { 
     571                type.tp_init = &wrapped_struct_init!(T).init; 
    625572            } 
    626573        } 
     
    634581    } 
    635582    Py_INCREF(cast(PyObject*)&type); 
    636     // Only directly expose a class to Python if it is a shim. 
    637     static if (!is(wrapping == void) || is(T U : U*) && is(U == struct)) { 
    638         PyModule_AddObject(Pyd_Module_p(modulename), name.ptr, cast(PyObject*)&type); 
    639     } 
     583    PyModule_AddObject(Pyd_Module_p(modulename), (name~\0).ptr, cast(PyObject*)&type); 
    640584 
    641585    is_wrapped!(T) = true; 
    642586    static if (is(T == class)) { 
     587        is_wrapped!(shim_class) = true; 
    643588        wrapped_classes[T.classinfo] = &type; 
    644         // If this is a class passed in by the user, create and wrap the shim. 
    645         // (By recursively calling this function.) 
    646         static if (is(wrapping == void)) { 
    647             alias make_wrapper!(T, Params).wrapper wrapper_class; 
    648             // Construct the recursive call. Since /this/ call to wrap_class 
    649             // was passed aliases to the members of the /base/ class, we need 
    650             // to pass the recursive call aliases to the members of the /shim/. 
    651             // The recursive_call template goes through each member of Params 
    652             // and constructs this. 
    653  
    654             // This is a workaround for some tuple shortcomings... 
    655             const char[] a = aliases!(0, Params); 
    656             pragma(msg, a); 
    657             mixin(a); 
    658  
    659             const char[] call = "wrap_class!(T, wrapper_class, name, "~recursive_call!("wrapper_class", 0, Params)~")();"; 
    660             pragma(msg, call); 
    661             mixin(call); 
    662             shim_class!(T) = &wrapped_class_type!(wrapper_class); 
    663         } 
     589        wrapped_classes[shim_class.classinfo] = &type; 
    664590    } 
    665591} 
  • trunk/infrastructure/pyd/ctor_wrap.d

    r100 r101  
    6565} 
    6666 
    67 // This template accepts a Tuple of (either) function pointer types or other 
    68 // Tuples, which each describe a ctor of T, and  uses them to wrap a Python 
    69 // tp_init function. 
     67// This template accepts a tuple of function pointer types, which each describe 
     68// a ctor of T, and  uses them to wrap a Python tp_init function. 
    7069template wrapped_ctors(T, C ...) { 
    7170    alias wrapped_class_object!(T) wrap_object; 
  • trunk/infrastructure/pyd/make_wrapper.d

    r100 r101  
    3434; 
    3535 
     36template T(A ...) { 
     37    alias A T; 
     38} 
     39template opFuncs() { 
     40    alias T!("opNeg", "opPos", "opCom", "opAdd", "opSub", "opMul", "opDiv", "opMod", "opAnd", "opOr", "opXor", "opShl", "opShr", "opCat", "opAddAssign", "opSubAssign", "opMulAssign", "opDivAssign", "opModAssign", "opAndAssign", "opOrAssign", "opXorAssign", "opShlAssign", "opShrAssign", "opCatAssign", "opIn_r", "opCmp", "opCall", "opApply", "opIndex", "opIndexAssign", "opSlice", "opSliceAssign", "length") opFuncs; 
     41} 
     42 
     43template funcTypes() { 
     44    alias T!("UNI", "UNI", "UNI", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "BIN", "UNSUPPORTED", "CMP", "CALL", "APPLY", "INDEX", "INDEXASS", "SLICE", "SLICEASS", "LEN") funcTypes; 
     45} 
     46template pyOpFuncs() { 
     47    alias T!("__neg__", "__pos__", "__invert__", "__add__", "__sub__", "__mul__", "__div__", "__mod__", "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", "__add__", "__iadd__", "__isub__", "__imul__", "__idiv__", "__imod__", "__iand__", "__ior__", "__ixor__", "__ilshift__", "__irshift__", "__iadd__", "UNSUPPORTED", "__cmp__", "__call__", "__iter__", "__getitem__", "__setitem__", "UNSUPPORTED", "UNSUPPORTED", "__len__") pyOpFuncs; 
     48} 
     49 
     50template opFunc(uint i) { 
     51    const char[] opFunc = opFuncs!()[i]; 
     52} 
     53 
     54template funcType(uint i) { 
     55    const char[] funcType = funcTypes!()[i]; 
     56} 
     57 
     58template pyOpFunc(uint i) { 
     59    const char[] pyOpFunc = pyOpFuncs!()[i]; 
     60} 
     61 
     62template op_shim(uint i) { 
     63    static if (funcType!(i) == "UNI" || funcType!(i) == "BIN" || funcType!(i) == "CMP" || funcType!("CALL")) { 
     64        const char[] op_shim = 
     65            "    ReturnType!(T."~opFunc!(i)~") "~opFunc!(i)~"(ParameterTypeTuple!(T."~opFunc!(i)~") t) {\n" 
     66            "        return __pyd_get_overload!(\""~opFunc!(i)~"\", typeof(&T."~opFunc!(i)~")).func(\""~pyOpFunc!(i)~"\", t);\n" 
     67            "    }\n"; 
     68    } else static if (funcType!(i) == "APPLY") { 
     69        const char[] op_shim = 
     70            "    int opApply(ParameterTypeTuple!(T.opApply)[0] dg) {\n" 
     71            "        return __pyd_apply_wrapper(dg);\n" 
     72            "    }\n"; 
     73    } else static assert(false, "Unsupported operator overload " ~ opFunc!(i)); 
     74} 
     75 
     76template op_shims(uint i, T) { 
     77    static if (i < opFuncs!().length) { 
     78        static if (is(typeof(mixin("&T."~opFunc!(i)))) && opFunc!(i) != "UNSUPPORTED") { 
     79            const char[] op_shims = op_shim!(i) ~ op_shims!(i+1, T); 
     80        } else { 
     81            const char[] op_shims = op_shims(i+1, T); 
     82        } 
     83    } else { 
     84        const char[] op_shims = ""; 
     85    } 
     86} 
     87 
    3688template OverloadShim() { 
     89    // If this is actually an instance of a Python subclass, return the 
     90    // PyObject associated with the object. Otherwise, return null. 
     91    PyObject* __pyd_get_pyobj() { 
     92        PyObject** _pyobj = cast(void*)this in wrapped_gc_objects; 
     93        PyTypeObject** _pytype = this.classinfo in wrapped_classes; 
     94        if (_pyobj is null || _pytype is null || (*_pyobj).ob_type != *_pytype) { 
     95            return *_pyobj; 
     96        } else { 
     97            return null; 
     98        } 
     99    } 
    37100    template __pyd_get_overload(char[] realname, fn_t) { 
    38101        ReturnType!(fn_t) func(T ...) (char[] name, T t) { 
    39             PyObject** _pyobj = cast(void*)this in wrapped_gc_objects; 
    40             PyTypeObject** _pytype = this.classinfo in wrapped_classes; 
    41             if (_pyobj is null || _pytype is null || (*_pyobj).ob_type != *_pytype) { 
     102            PyObject* _pyobj = this.__pyd_get_pyobj(); 
     103            if (_pyobj !is null) { 
    42104                // If this object's type is not the wrapped class's type (that is, 
    43105                // if this object is actually a Python subclass of the wrapped 
    44106                // class), then call the Python object. 
    45                 PyObject* method = PyObject_GetAttrString(*_pyobj, (name ~ \0).ptr); 
     107                PyObject* method = PyObject_GetAttrString(_pyobj, (name ~ \0).ptr); 
    46108                if (method is null) handle_exception(); 
    47109                auto pydg = PydCallable_AsDelegate!(fn_to_dg!(fn_t))(method); 
     
    51113                mixin("return super."~realname~"(t);"); 
    52114            } 
     115        } 
     116    } 
     117    int __pyd_apply_wrapper(dg_t) (dg_t dg) { 
     118        alias ParameterTypeTuple!(dg_t)[0] arg_t; 
     119        const uint args = ParameterTypeTuple!(dg_t).length; 
     120        PyObject* _pyobj = this.__pyd_get_pyobj(); 
     121        if (_pyobj !is null) { 
     122            PyObject* iter = PyObject_GetIter(_pyobj); 
     123            if (iter is null) handle_exception(); 
     124            PyObject* item; 
     125            int result = 0; 
     126 
     127            item = PyIter_Next(iter); 
     128            while (item) { 
     129                static if (args == 1 && is(arg_t == PyObject*)) { 
     130                    result = dg(item); 
     131                } else { 
     132                    if (PyTuple_Check(item)) { 
     133                        result = applyPyTupleToDelegate(dg, item); 
     134                    } else { 
     135                        static if (args == 1) { 
     136                            arg_t t = d_type!(typeof(arg_t))(item); 
     137                            result = dg(t); 
     138                        } else { 
     139                            throw new Exception("Tried to override opApply with wrong number of args..."); 
     140                        } 
     141                    } 
     142                } 
     143                Py_DECREF(item); 
     144                if (result) break; 
     145                item = PyIter_Next(iter); 
     146            } 
     147            Py_DECREF(iter); 
     148            handle_exception(); 
     149            return result; 
     150        } else { 
     151            return super.opApply(dg); 
    53152        } 
    54153    } 
     
    68167    "    mixin OverloadShim;\n"~ 
    69168    class_decls!(0, Params)~"\n"~ 
     169//    op_shims!(0, T)~ 
    70170    "}\n"; 
    71171    pragma(msg, cls); 
  • trunk/infrastructure/pyd/struct_wrap.d

    r100 r101  
    6464 
    6565struct Member(char[] realname, char[] name=realname) { 
    66     static void call(T) () { 
     66    static void call(T, dummy) () { 
    6767        pragma(msg, "struct.member: " ~ name); 
    6868        static PyGetSetDef empty = {null, null, null, null, null};