Changeset 52
- Timestamp:
- 12/10/06 18:02:59 (2 years ago)
- Files:
-
- trunk/dcompiler.py (modified) (1 diff)
- trunk/examples/testdll/test.py (modified) (1 diff)
- trunk/examples/testdll/testdll.d (modified) (2 diffs)
- trunk/html_doc/basics.html (modified) (1 diff)
- trunk/html_doc/celerid.html (modified) (1 diff)
- trunk/html_doc/class_wrapping.html (modified) (4 diffs)
- trunk/html_doc/conversion.html (modified) (3 diffs)
- trunk/html_doc/credits.html (modified) (1 diff)
- trunk/html_doc/except_wrapping.html (modified) (1 diff)
- trunk/html_doc/func_wrapping.html (modified) (2 diffs)
- trunk/html_doc/index.html (modified) (1 diff)
- trunk/html_doc/install.html (modified) (1 diff)
- trunk/html_doc/pydobject.html (modified) (1 diff)
- trunk/html_doc/struct_wrapping.html (added)
- trunk/infrastructure/pyd/class_wrap.d (modified) (9 diffs)
- trunk/infrastructure/pyd/ctor_wrap.d (modified) (2 diffs)
- trunk/infrastructure/pyd/def.d (modified) (1 diff)
- trunk/infrastructure/pyd/func_wrap.d (modified) (1 diff)
- trunk/infrastructure/pyd/iteration.d (modified) (3 diffs)
- trunk/infrastructure/pyd/make_object.d (modified) (10 diffs)
- trunk/infrastructure/pyd/pyd.d (modified) (1 diff)
- trunk/infrastructure/pyd/struct_wrap.d (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dcompiler.py
r51 r52 37 37 'pyd.d', 38 38 'pydobject.d', 39 'struct_wrap.d', 39 40 ] 40 41 trunk/examples/testdll/test.py
r37 r52 37 37 print 38 38 39 S = testdll.S 40 s = S() 41 print "s.s = 'hello'" 42 s.s = 'hello' 43 print "s.s" 44 print s.s 45 print "s.write_s()" 46 s.write_s() 47 48 print 49 39 50 print '--------' 40 51 print 'SUCCESS' trunk/examples/testdll/testdll.d
r45 r52 110 110 } 111 111 112 struct S { 113 int i; 114 char[] s; 115 void write_s() { 116 writefln(s); 117 } 118 } 119 112 120 Foo spam(Foo f) { 113 121 f.foo(); … … 142 150 f.prop!(Foo.i); 143 151 finalize_class(f); 152 153 wrapped_struct!(S) s; 154 s.def!(S.write_s); 155 const size_t i = S.i.offsetof; 156 const size_t t = S.s.offsetof; 157 s.member!(int, i, "i"); 158 s.member!(char[], t, "s"); 159 finalize_struct(s); 144 160 } 145 161 trunk/html_doc/basics.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/celerid.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/class_wrapping.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="navcur" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> … … 40 41 <dd>This wraps a method of the class. It functions exactly like the <code>def</code> function used to <a href="func_wrapping.html">wrap regular functions</a>, with one very important difference: There is no support for default arguments. (This is a side-effect of the fact that you cannot call an alias of a method in D, and delegates do not understand default arguments.)</dd> 41 42 43 <dt><code>static void static_def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn)) ();</code></dt> 44 <dd>This wraps a static member function of the class. It also functions exactly like the <code>def</code> function used to wrap regular functions, and even includes support for default arguments.</dd> 45 42 46 <dt><code>static void prop(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), bool <span class="t_arg">RO</span> = false) ();</code></dt> 43 47 <dd>This wraps a property. See the examples below for more details. … … 45 49 <li><span class="t_arg">fn</span> is the name of the property. <code>prop</code> will automatically attempt to wrap both the "get" and "set" forms of the property, unless <span class="t_arg">RO</span> is specified.</li> 46 50 <li><span class="t_arg">name</span> is the name of the property as it will appear in Python. As with <code>def</code>, <code>prop</code> will attempt to derive this automatically.</li> 47 <li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. (This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)</li>51 <li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. <i>(This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)</i></li> 48 52 </ul> 49 53 </dd> … … 86 90 87 91 <p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>wrapped_class.alt_iter</code>.</p> 92 93 <p>Also missing from the list is <code>opAssign</code>. Python has strict reference semantics for its objects, so overloading the assignment operator is not possible. You must explicitly wrap <code>opAssign</code> with a regular method.</p> 88 94 89 95 <p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p> trunk/html_doc/conversion.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> … … 40 41 <tr><td>idouble, cdouble</td> <td>complex</td> </tr> 41 42 <tr><td>char[] (as ASCII string)</td> <td>str</td> </tr> 42 < tr><td>wchar[] (as UCS2 string)</td> <td>unicode</td> </tr>43 <!--<tr><td>wchar[] (as UCS2 string)</td> <td>unicode</td> </tr>--> 43 44 <tr><td>dynamic array</td> <td>list</td> </tr> 44 45 <tr><td>associative array</td> <td>dict</td> </tr> 45 46 <tr><td>delegate or function pointer</td> <td>A callable object</td></tr> 46 47 <tr><td><a href="class_wrapping.html">A wrapped class</a></td> <td>The wrapped type</td></tr> 48 <tr><td><a href="struct_wrapping.html">A wrapped struct</a></td> <td>The wrapped type</td></tr> 49 <tr><td>Pointer-to-wrapped-struct</td> <td>The wrapped type</td></tr> 47 50 <tr><td><a href="pydobject.html">PydObject</a></td> <td>The wrapped object's type</td></tr> 48 51 <tr><td>PyObject*</td> <td>The object's type</td></tr> … … 61 64 <tr><td>Any type</td> <td>PyObject*</td> </tr> 62 65 <tr><td>Any type</td> <td><a href="pydobject.html">PydObject</a></td></tr> 66 <tr><td><a href="struct_wrapping.html">Wrapped struct</a></td> <td>Wrapped struct</td></tr> 67 <tr><td><a href="struct_wrapping.html">Wrapped struct</a></td> <td>Pointer to wrapped struct</td></tr> 63 68 <tr><td><a href="class_wrapping.html">Wrapped class</a></td> <td>Wrapped class</td></tr> 64 69 <tr><td>Any callable</td> <td>delegate</td> </tr> trunk/html_doc/credits.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/except_wrapping.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="navcur" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/func_wrapping.html
r49 r52 17 17 <a class="navcur" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> … … 36 37 </ul> 37 38 38 <p>All calls to <code>def</code> must occur <em>before</em> calling <code>module_init</code>. Any function whose return type and arguments are <a href="conversion.html">convert able</a> can be wrapped by <code>def</code>. <code>def</code> can only wrap functions with <code>in</code> arguments (not <code>out</code> or <code>inout</code>). <code>def</code> also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:</p>39 <p>All calls to <code>def</code> must occur <em>before</em> calling <code>module_init</code>. Any function whose return type and arguments are <a href="conversion.html">convertible</a> can be wrapped by <code>def</code>. <code>def</code> can only wrap functions with <code>in</code> arguments (not <code>out</code> or <code>inout</code> or <code>lazy</code>). <code>def</code> also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:</p> 39 40 40 41 <pre class="code"><span class="keyword">import</span> pyd.pyd; trunk/html_doc/index.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/install.html
r51 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="nav" href="pydobject.html">PydObject</a><br /> trunk/html_doc/pydobject.html
r49 r52 17 17 <a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 18 18 <a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 19 <a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 19 20 <a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 20 21 <a class="navcur" href="pydobject.html">PydObject</a><br /> trunk/infrastructure/pyd/class_wrap.d
r51 r52 111 111 } 112 112 113 // The set of all instances of this class that are passed into Python. Keeping 114 // references here in D is needed to keep the GC happy. The integer value is 115 // used to make this a sort of poor man's multiset. 116 template wrap_class_instances(T) { 117 int[T] wrap_class_instances; 118 } 113 // A mapping of all objects referenced by the GC that are being held by Python. 114 PyObject*[void*] wrapped_gc_objects; 119 115 120 116 /** … … 165 161 extern(C) 166 162 void wrapped_dealloc(PyObject* self) { 167 //exception_catcher(delegate PyObject*() { 168 try { 163 exception_catcher(delegate void() { 169 164 WrapPyObject_SetObj(self, null); 170 } catch { } 171 self.ob_type.tp_free(self); 172 return null; 173 //}); 165 self.ob_type.tp_free(self); 166 }); 174 167 } 175 168 } … … 245 238 * wrapping the specific parts of the class. 246 239 */ 247 template wrapped_class(T, char[] classname = symbolnameof!(T)) { 248 pragma(msg, "wrapped_class: " ~ classname); 249 struct wrapped_class { 250 static const char[] _name = classname; 251 T t = null; 252 /** 253 * Wraps a member function of the class. 254 * 255 * Params: 256 * name = The name of the function as it will appear in Python. 257 * fn = The member function to wrap. 258 * MIN_ARGS = The minimum number of arguments this function can accept. 259 * fn_t = The type of the function. It is only useful to specify this 260 * if more than one function has the same name as this one. 261 */ 262 template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) { 263 pragma(msg, "class.def: " ~ name); 264 static void def() { 265 static PyMethodDef empty = { null, null, 0, null }; 266 alias wrapped_method_list!(T) list; 267 list[length-1].ml_name = name ~ \0; 268 list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 269 list[length-1].ml_flags = METH_VARARGS; 270 list[length-1].ml_doc = ""; 271 list ~= empty; 272 // It's possible that appending the empty item invalidated the 273 // pointer in the type struct, so we renew it here. 274 wrapped_class_type!(T).tp_methods = list; 275 } 240 struct wrapped_class(T, char[] classname = symbolnameof!(T)) { 241 static if (is(T == class)) pragma(msg, "wrapped_class: " ~ classname); 242 static const char[] _name = classname; 243 alias T wrapped_type; 244 /** 245 * Wraps a member function of the class. 246 * 247 * Params: 248 * fn = The member function to wrap. 249 * name = The name of the function as it will appear in Python. 250 * fn_t = The type of the function. It is only useful to specify this 251 * if more than one function has the same name as this one. 252 */ 253 static void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) () { 254 pragma(msg, "class.def: " ~ name); 255 static PyMethodDef empty = { null, null, 0, null }; 256 alias wrapped_method_list!(T) list; 257 list[length-1].ml_name = (name ~ \0).ptr; 258 list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 259 list[length-1].ml_flags = METH_VARARGS; 260 list[length-1].ml_doc = ""; 261 list ~= empty; 262 // It's possible that appending the empty item invalidated the 263 // pointer in the type struct, so we renew it here. 264 wrapped_class_type!(T).tp_methods = list; 265 } 266 267 /** 268 * Wraps a static member function of the class. Identical to pyd.def.def 269 */ 270 static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) () { 271 pragma(msg, "class.static_def: " ~ name); 272 static PyMethodDef empty = { null, null, 0, null }; 273 alias wrapped_method_list!(T) list; 274 list[length-1].ml_name = (name ~ \0).ptr; 275 list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; 276 list[length-1].ml_flags = METH_VARARGS | METH_STATIC; 277 list[length-1].ml_doc = ""; 278 list ~= empty; 279 wrapped_class_type!(T).tp_methods = list; 280 } 281 282 /** 283 * Wraps a property of the class. 284 * 285 * Params: 286 * fn = The property to wrap. 287 * name = The name of the property as it will appear in Python. 288 * RO = Whether this is a read-only property. 289 */ 290 static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) () { 291 pragma(msg, "class.prop: " ~ name); 292 static PyGetSetDef empty = { null, null, null, null, null }; 293 wrapped_prop_list!(T)[length-1].name = name ~ \0; 294 wrapped_prop_list!(T)[length-1].get = 295 &wrapped_get!(T, fn).func; 296 static if (!RO) { 297 wrapped_prop_list!(T)[length-1].set = 298 &wrapped_set!(T, fn).func; 276 299 } 277 278 /** 279 * Wraps a property of the class. 280 * 281 * Params: 282 * name = The name of the property as it will appear in Python. 283 * fn = The property to wrap. 284 * RO = Whether this is a read-only property. 285 */ 286 template prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) { 287 pragma(msg, "class.prop: " ~ name); 288 static void prop() { 289 static PyGetSetDef empty = { null, null, null, null, null }; 290 wrapped_prop_list!(T)[length-1].name = name ~ \0; 291 wrapped_prop_list!(T)[length-1].get = 292 &wrapped_get!(T, fn).func; 293 static if (!RO) { 294 wrapped_prop_list!(T)[length-1].set = 295 &wrapped_set!(T, fn).func; 296 } 297 wrapped_prop_list!(T)[length-1].doc = ""; 298 wrapped_prop_list!(T)[length-1].closure = null; 299 wrapped_prop_list!(T) ~= empty; 300 // It's possible that appending the empty item invalidated the 301 // pointer in the type struct, so we renew it here. 302 wrapped_class_type!(T).tp_getset = 303 wrapped_prop_list!(T); 304 } 305 } 306 307 /** 308 * Wraps the constructors of the class. 309 * 310 * This template takes a series of specializations of the ctor template 311 * (see ctor_wrap.d), each of which describes a different constructor 312 * that the class supports. The default constructor need not be 313 * specified, and will always be available if the class supports it. 314 * 315 * Bugs: 316 * This currently does not support having multiple constructors with 317 * the same number of arguments. 318 */ 319 static void init(C ...) () { 320 wrapped_class_type!(T).tp_init = 321 &wrapped_ctors!(T, C).init_func; 322 } 323 324 // Iteration wrapping support requires StackThreads 325 version(Pyd_with_StackThreads) { 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 PydStackContext_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 PydStackContext_Ready(); 346 list[length-1].ml_name = name ~ \0; 347 list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; 348 list[length-1].ml_flags = METH_VARARGS; 349 list[length-1].ml_doc = ""; 350 list ~= empty; 351 // It's possible that appending the empty item invalidated the 352 // pointer in the type struct, so we renew it here. 353 wrapped_class_type!(T).tp_methods = list; 354 } 355 356 } /*Pyd_with_StackThreads*/ 357 } 300 wrapped_prop_list!(T)[length-1].doc = ""; 301 wrapped_prop_list!(T)[length-1].closure = null; 302 wrapped_prop_list!(T) ~= empty; 303 // It's possible that appending the empty item invalidated the 304 // pointer in the type struct, so we renew it here. 305 wrapped_class_type!(T).tp_getset = 306 wrapped_prop_list!(T); 307 } 308 309 /** 310 * Wraps the constructors of the class. 311 * 312 * This template takes a series of specializations of the ctor template 313 * (see ctor_wrap.d), each of which describes a different constructor 314 * that the class supports. The default constructor need not be 315 * specified, and will always be available if the class supports it. 316 * 317 * Bugs: 318 * This currently does not support having multiple constructors with 319 * the same number of arguments. 320 */ 321 static void init(C ...) () { 322 wrapped_class_type!(T).tp_init = 323 &wrapped_ctors!(T, C).init_func; 324 } 325 326 // Iteration wrapping support requires StackThreads 327 version(Pyd_with_StackThreads) { 328 329 /** 330 * Allows selection of alternate opApply overloads. iter_t should be 331 * the type of the delegate in the opApply function that the user wants 332 * to be the default. 333 */ 334 static void iter(iter_t) () { 335 PydStackContext_Ready(); 336 wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 337 } 338 339 /** 340 * Exposes alternate iteration methods, originally intended for use with 341 * D's delegate-as-iterator features, as methods returning a Python 342 * iterator. 343 */ 344 static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) () { 345 static PyMethodDef empty = { null, null, 0, null }; 346 alias wrapped_method_list!(T) list; 347 PydStackContext_Ready(); 348 list[length-1].ml_name = name ~ \0; 349 list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; 350 list[length-1].ml_flags = METH_VARARGS; 351 list[length-1].ml_doc = ""; 352 list ~= empty; 353 // It's possible that appending the empty item invalidated the 354 // pointer in the type struct, so we renew it here. 355 wrapped_class_type!(T).tp_methods = list; 356 } 357 358 } /*Pyd_with_StackThreads*/ 358 359 } 359 360 … … 363 364 */ 364 365 void finalize_class(CLS) (CLS cls, char[] modulename="") { 365 alias typeof(cls.t)T;366 alias CLS.wrapped_type T; 366 367 alias wrapped_class_type!(T) type; 367 368 const char[] name = CLS._name; 368 pragma(msg, "finalize_class: " ~ name); 369 static if (is(T == class)) { 370 pragma(msg, "finalize_class: " ~ name); 371 } else { 372 pragma(msg, "finalize_struct: " ~ name); 373 } 374 pragma(msg, "finalize_class, T is " ~ prettytypeof!(T)); 369 375 370 assert(Pyd_Module_p !is null, "Must initialize module before wrapping classes.");376 assert(Pyd_Module_p(modulename) !is null, "Must initialize module before wrapping classes."); 371 377 char[] module_name = toString(PyModule_GetName(Pyd_Module_p(modulename))); 372 378 // Fill in missing values 373 379 type.ob_type = PyType_Type_p(); 374 //type.tp_new = &(wrapped_methods!(T).wrapped_new);375 //type.tp_dealloc = &(wrapped_methods!(T).wrapped_dealloc);376 380 type.tp_basicsize = (wrapped_class_object!(T)).sizeof; 377 381 type.tp_doc = name ~ " objects" ~ \0; 378 382 type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 379 //type.tp_new = &PyType_GenericNew;380 383 //type.tp_repr = &wrapped_repr!(T).repr; 381 384 type.tp_methods = wrapped_method_list!(T); … … 415 418 416 419 // If a ctor wasn't supplied, try the default. 417 //if (type.tp_init is null) { 418 // type.tp_init = &wrapped_init!(T).init; 419 //} 420 if (type.tp_init is null) { 421 static if (is(T == class)) { 422 type.tp_init = &wrapped_init!(T).init; 423 } else { 424 type.tp_init = &wrapped_struct_init!(T).init; 425 } 426 } 420 427 if (PyType_Ready(&type) < 0) { 421 428 // XXX: This will probably crash the interpreter, as it isn't normally … … 432 439 // PYD API FUNCTIONS // 433 440 /////////////////////// 441 442 private union aa_reference(T) { 443 T aa; 444 void* ptr; 445 } 446 447 private void* get_voidptr(T)(T t) { 448 static if (isAA!(T)) { 449 aa_reference!(T) ref; 450 ref.aa = t; 451 return ref.ptr; 452 } else { 453 return cast(void*)t; 454 } 455 } 434 456 435 457 /** … … 440 462 alias wrapped_class_type!(T) type; 441 463 if (is_wrapped!(T)) { 442 // Allocate the object 443 wrapped_object* obj = 444 cast(wrapped_object*)type.tp_new(&type, null, null); 464 // If this object is already wrapped, get the existing object. 465 PyObject** obj_p = get_voidptr(t) in wrapped_gc_objects; 466 if (obj_p) return *obj_p; 467 // Otherwise, allocate a new object 468 PyObject* obj = type.tp_new(&type, null, null); 445 469 // Set the contained instance 446 470 WrapPyObject_SetObj(obj, t); 447 return cast(PyObject*)obj;471 return obj; 448 472 } else { 449 473 PyErr_SetString(PyExc_RuntimeError, "Type " ~ typeid(T).toString() ~ " is not wrapped by Pyd."); … … 460 484 wrapped_object* self = cast(wrapped_object*)_self; 461 485 if (!is_wrapped!(T) || self is null || !PyObject_TypeCheck(_self, &type)) { 462 // Throw something486 throw new Exception("Error extracting D object from Python object..."); 463 487 } 464 488 return self.d_obj; … … 471 495 alias wrapped_class_object!(T) obj; 472 496 obj* self = cast(obj*)_self; 497 if (get_voidptr(t) == get_voidptr(self.d_obj)) 498 return; 473 499 // Clean up the old object, if there is one 474 500 if (self.d_obj !is null) { 475 wrap_class_instances!(T)[self.d_obj]--; 476 if (wrap_class_instances!(T)[self.d_obj] <= 0) { 477 wrap_class_instances!(T).remove(self.d_obj); 478 } 501 wrapped_gc_objects.remove(get_voidptr(self.d_obj)); 479 502 } 480 503 self.d_obj = t; 481 504 // Handle the new one, if there is one 482 if (t !is null) wrap _class_instances!(T)[t]++;483 } 484 505 if (t !is null) wrapped_gc_objects[get_voidptr(self.d_obj)] = _self; 506 } 507 trunk/infrastructure/pyd/ctor_wrap.d
r50 r52 28 28 private import pyd.make_object; 29 29 30 private import meta.Nameof; 31 30 32 private import std.traits; 31 33 … … 36 38 // The default __init__ method calls the class's zero-argument constructor. 37 39 template wrapped_init(T) { 38 alias wrapped_class_object!(T) wrap_object;39 40 extern(C) 40 41 int init(PyObject* self, PyObject* args, PyObject* kwds) { 41 42 return exception_catcher({ 42 43 WrapPyObject_SetObj(self, new T); 44 return 0; 45 }); 46 } 47 } 48 49 // The __init__ slot for wrapped structs. T is of the type of a pointer to the 50 // struct. 51 template wrapped_struct_init(T) { 52 extern(C) 53 int init(PyObject* self, PyObject* args, PyObject* kwds) { 54 return exception_catcher({ 55 static if (is(T S : S*)) { 56 pragma(msg, "wrapped_struct_init, S is " ~ prettynameof!(S)); 57 T t = new S; 58 WrapPyObject_SetObj(self, t); 59 } 43 60 return 0; 44 61 }); trunk/infrastructure/pyd/def.d
r51 r52 37 37 38 38 PyObject* Pyd_Module_p(char[] modulename="") { 39 return pyd_modules[modulename]; 39 PyObject** m = modulename in pyd_modules; 40 if (m is null) return null; 41 else return *m; 40 42 } 41 43 trunk/infrastructure/pyd/func_wrap.d
r50 r52 39 39 40 40 // Builds a callable Python object from a delegate or function pointer. 41 PyObject* PydFunc_FromDelegate(T) (T dg) {41 void PydWrappedFunc_Ready(T)() { 42 42 alias wrapped_class_type!(T) type; 43 43 alias wrapped_class_object!(T) obj; 44 44 if (!is_wrapped!(T)) { 45 45 type.ob_type = PyType_Type_p; 46 type.tp_new = &wrapped_methods!(T).wrapped_new;47 type.tp_dealloc = &wrapped_methods!(T).wrapped_dealloc;48 46 type.tp_basicsize = obj.sizeof; 49 47 type.tp_name = "PydFunc"; 48 50 49 type.tp_call = &wrapped_func_call!(T).call; 50 51 51 PyType_Ready(&type); 52 52 is_wrapped!(T) = true; 53 53 wrapped_classes[typeid(T)] = true; 54 54 } 55 obj* func = cast(obj*)type.tp_new(&type, null, null);56 func.d_obj = dg;57 wrap_class_instances!(T)[dg]++;58 return cast(PyObject*)func;59 55 } 60 56 trunk/infrastructure/pyd/iteration.d
r51 r52 60 60 // enclosing function's stack frame. 61 61 StackContext.yield(); 62 PyObject* temp;63 62 64 63 t(delegate int(inout Info i) { … … 116 115 if (!is_wrapped!(StackContext)) { 117 116 type.ob_type = PyType_Type_p; 118 //type.tp_new = &wrapped_methods!(StackContext).wrapped_new;119 //type.tp_dealloc = &wrapped_methods!(StackContext).wrapped_dealloc;120 117 type.tp_basicsize = PydSC_object.sizeof; 121 118 type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 122 //type.tp_doc = "";123 119 type.tp_name = "PydOpApplyWrapper"; 124 120 … … 127 123 128 124 PyType_Ready(&type); 129 130 // Mark the class as ready131 125 is_wrapped!(StackContext) = true; 132 126 wrapped_classes[typeid(StackContext)] = true; trunk/infrastructure/pyd/make_object.d
r51 r52 38 38 39 39 import std.string; 40 //import std.stdio; 40 41 41 42 import pyd.pydobject; … … 44 45 import pyd.exception; 45 46 46 p rivate template isArray(T) {47 package template isArray(T) { 47 48 const bool isArray = is(typeof(T.init[0])[] == T); 48 49 } … … 55 56 // say "!is(typeof(T.init) == T)"; however, this template has the advantage of 56 57 // being easily fixable should this behavior for static arrays change. 57 p rivate template isStaticArray(T) {58 package template isStaticArray(T) { 58 59 const bool isStaticArray = is(typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T); 59 60 } 60 61 61 p rivate template isAA(T) {62 package template isAA(T) { 62 63 const bool isAA = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); 63 64 } … … 89 90 return PyComplex_FromDoubles(t.re, t.im); 90 91 } else static if (is(T : char[])) { 91 return PyString_FromString( t ~ \0);92 return PyString_FromString((t ~ \0).ptr); 92 93 } else static if (is(T : wchar[])) { 93 94 return PyUnicode_FromWideChar(t, t.length); … … 132 133 return dict; 133 134 } else static if (is(T == delegate) || is(T == function)) { 134 return PydFunc_FromDelegate!(T)(t); 135 PydWrappedFunc_Ready!(T)(); 136 return WrapPyObject_FromObject(t); 135 137 } else static if (is(T : PydObject)) { 136 138 PyObject* temp = t.ptr(); … … 139 141 // Convert wrapped type of a PyObject* 140 142 } else static if (is(T == class)) { 141 // Put only if it actually is a wrapped type. :-)143 // But only if it actually is a wrapped type. :-) 142 144 if (is_wrapped!(T)) { 143 145 return WrapPyObject_FromObject(t); 144 146 } 145 147 // If it's not a wrapped type, fall through to the exception. 148 // If converting a struct by value, create a copy and wrap that 149 } else static if (is(T == struct)) { 150 if (is_wrapped!(T*)) { 151 T* temp = new T; 152 *temp = t; 153 return WrapPyObject_FromObject(temp); 154 } 155 // If converting a struct by reference, wrap the thing directly 156 } else static if (is(typeof(*t) == struct)) { 157 if (is_wrapped!(T)) { 158 return WrapPyObject_FromObject(t); 159 } 146 160 // The function expects to be passed a borrowed reference and return an 147 161 // owned reference. Thus, if passed a PyObject*, this will increment the … … 227 241 return Py_None; 228 242 } else static if (is(T == class)) { 229 static if (is(T == Object)) {230 pragma(msg, "d_type: T is Object");231 }232 243 // We can only convert to a class if it has been wrapped, and of course 233 244 // we can only convert the object if it is the wrapped type. … … 237 248 // Otherwise, throw up an exception. 238 249 could_not_convert!(T)(o); 250 } else static if (is(T == struct)) { // struct by value 251 if (is_wrapped!(T*) && PyObject_TypeCheck(o, &wrapped_class_type!(T*))) { 252 return *WrapPyObject_AsObject!(T*)(o); 253 } else could_not_convert!(T)(o); 254 } else static if (is(typeof(*(T.init)) == struct)) { // pointer to struct 255 if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 256 return WrapPyObject_AsObject!(T)(o); 257 } else could_not_convert!(T)(o); 239 258 } else static if (is(T == delegate)) { 240 if (PyCallable_Check(o)) { 259 // Get the original wrapped delegate out if this is a wrapped delegate 260 if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 261 return WrapPyObject_AsObject!(T)(o); 262 // Otherwise, wrap the PyCallable with a delegate 263 } else if (PyCallable_Check(o)) { 241 264 return PydCallable_AsDelegate!(T)(o); 265 } else could_not_convert!(T)(o); 266 } else static if (is(T == function)) { 267 // We can only make it a function pointer if we originally wrapped a 268 // function pointer. 269 if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 270 return WrapPyObject_AsObject!(T)(o); 242 271 } else could_not_convert!(T)(o); 243 272 /+ … … 249 278 +/ 250 279 } else static if (is(char[] : T)) { 280 //writefln("d_type!(char[])"); 251 281 char* result; 252 282 PyObject* repr; … … 262 292 } 263 293 if (result is null) handle_exception(); 264 return .toString(result); 294 //char[] s = .toString(result); 295 //writefln("result is |%s|", result); 296 //writefln("s is |%s|", s); 297 return .toString(result).dup; 265 298 } else static if (is(cdouble : T)) { 266 299 double real_ = PyComplex_RealAsDouble(o); trunk/infrastructure/pyd/pyd.d
r51 r52 34 34 import pyd.make_object; 35 35 import pyd.pydobject; 36 import pyd.struct_wrap; 36 37 37 38 // Importing these is only needed as a workaround to bug #311
