Changeset 40
- Timestamp:
- 10/24/06 01:24:13 (2 years ago)
- Files:
-
- trunk/credits.txt (added)
- trunk/dcompiler.py (modified) (5 diffs)
- trunk/examples/testdll/testdll.d (modified) (5 diffs)
- trunk/html_doc/basics.html (modified) (1 diff)
- trunk/infrastructure/meta (added)
- trunk/infrastructure/meta/Apply.d (added)
- trunk/infrastructure/meta/Bind.d (added)
- trunk/infrastructure/meta/Default.d (added)
- trunk/infrastructure/meta/Demangle.d (added)
- trunk/infrastructure/meta/FuncMeta.d (added)
- trunk/infrastructure/meta/Instantiate.d (added)
- trunk/infrastructure/meta/Nameof.d (added)
- trunk/infrastructure/meta/Tuple.d (added)
- trunk/infrastructure/meta/Use.d (added)
- trunk/infrastructure/meta/Util.d (added)
- trunk/infrastructure/meta/VarArg.d (added)
- trunk/infrastructure/pyd/class_wrap.d (modified) (5 diffs)
- trunk/infrastructure/pyd/ctor_wrap.d (modified) (3 diffs)
- trunk/infrastructure/pyd/def.d (modified) (2 diffs)
- trunk/infrastructure/pyd/dg_convert.d (modified) (2 diffs)
- trunk/infrastructure/pyd/ftype.d (deleted)
- trunk/infrastructure/pyd/func_wrap.d (modified) (11 diffs)
- trunk/infrastructure/pyd/generators/min_args.py (modified) (1 diff)
- trunk/infrastructure/pyd/generators/min_args.txt (modified) (1 diff)
- trunk/infrastructure/pyd/iteration.d (modified) (4 diffs)
- trunk/infrastructure/pyd/tuples.d (deleted)
- trunk/infrastructure/st/stackcontext.d (modified) (33 diffs)
- trunk/infrastructure/st/stackthread.d (modified) (1 diff)
- trunk/infrastructure/st/tls.d (added)
- trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dcompiler.py
r37 r40 32 32 'dpyobject.d', 33 33 'exception.d', 34 'ftype.d',34 # 'ftype.d', 35 35 'func_wrap.d', 36 36 'iteration.d', … … 38 38 'op_wrap.d', 39 39 'pyd.d', 40 'tuples.d',40 # 'tuples.d', 41 41 ] 42 42 … … 45 45 'stackcontext.d', 46 46 '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', 47 62 ] 48 63 … … 162 177 if not os.path.isfile(filePath): 163 178 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 165 188 ) 166 189 sources.append(filePath) … … 380 403 self._debugOpt = '-debug=%s' 381 404 # _defaultOptimizeOpts 382 self._defaultOptimizeOpts = ['-debug' , '-unittest']405 self._defaultOptimizeOpts = ['-debug'] 383 406 # _debugOptimizeOpts 384 self._debugOptimizeOpts = self._defaultOptimizeOpts + ['- g']407 self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-unittest', '-g'] 385 408 # _releaseOptimizeOpts 386 409 self._releaseOptimizeOpts = ['-version=Optimized', '-release', '-O', '-inline'] trunk/examples/testdll/testdll.d
r38 r40 6 6 import std.stdio; 7 7 8 import meta.Tuple; 9 import meta.Apply; 10 8 11 void apply_test(int i, char[] s) { 9 12 writefln("%s %s", i, s); … … 11 14 12 15 void 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); 28 21 } 29 22 … … 47 40 int m_i; 48 41 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 } 51 48 void foo() { 52 49 writefln("Foo.foo(): i = %s", m_i); … … 109 106 extern (C) 110 107 export void inittestdll() { 111 def!(foo , "foo");108 def!(foo/*, "foo"*/); 112 109 // Python does not support function overloading. This allows us to wrap 113 110 // an overloading function under a different name. Note that if the … … 132 129 wrapped_class!(Foo, "Foo") f; 133 130 // Constructor wrapping 134 f.init!( tuple!(int), tuple!(int, int));131 f.init!(void function(int), void function(int, int)); 135 132 // Member function wrapping 136 133 f.def!(Foo.foo, "foo"); trunk/html_doc/basics.html
r39 r40 28 28 <p>Pyd requires Python 2.4 or newer and the latest version of DMD.</p> 29 29 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> 31 31 32 32 <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 22 22 module pyd.class_wrap; 23 23 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; 24 private { 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 } 37 41 38 42 bool[TypeInfo] wrapped_classes; … … 168 172 // This may be either the getter or the setter 169 173 alias typeof(&p) p_t; 174 alias funcDelegInfoT!(p_t) Info; 170 175 // This means it's the getter 171 static if ( NumberOfArgs!(p_t)== 0) {176 static if (Info.numArgs == 0) { 172 177 alias p_t getter_type; 173 178 // The setter may return void, or it may return the newly set attribute. 174 alias typeof(p(Ret urnType!(p_t).init)) function(ReturnType!(p_t)) setter_type;179 alias typeof(p(RetType!(p_t).init)) function(RetType!(p_t)) setter_type; 175 180 // This means it's the setter 176 181 } else { 177 182 alias p_t setter_type; 178 alias ArgType!(p_t, 1) function() getter_type;183 alias Info.Meta.ArgType!(0) function() getter_type; 179 184 } 180 185 } … … 258 263 * if more than one function has the same name as this one. 259 264 */ 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)) { 261 266 pragma(msg, "class.def: " ~ name); 262 267 static void def() { … … 315 320 * the same number of arguments. 316 321 */ 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; 322 353 } 323 354 } … … 350 381 351 382 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 } 354 387 } 355 388 trunk/infrastructure/pyd/ctor_wrap.d
r37 r40 27 27 private import pyd.func_wrap; 28 28 private import pyd.make_object; 29 private import pyd.tuples;30 29 31 template outer(T) { 30 private import meta.Tuple; 31 private import meta.Bind; 32 private import meta.Instantiate; 33 34 template ctor_redirect(T) { 32 35 T call_ctor()() { 33 36 return new T(); … … 75 78 } 76 79 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. 83 template wrapped_ctors(T, Tu) { 79 84 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 81 126 extern(C) 82 127 int init_func(PyObject* self, PyObject* args, PyObject* kwds) { … … 91 136 } 92 137 } 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); 180 139 }); 181 140 } trunk/infrastructure/pyd/def.d
r28 r40 27 27 private import pyd.dg_convert; 28 28 private import pyd.exception; 29 private import pyd.ftype;30 29 private import pyd.func_wrap; 31 30 private import pyd.make_object; 31 32 private import meta.Default; 33 private import meta.Nameof; 32 34 33 35 private import std.string; … … 77 79 *It's greater than 10!) 78 80 */ 79 template def(alias fn, char[] name , fn_t=typeof(&fn), uint MIN_ARGS = MIN_ARGS!(fn)) {81 template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS = minArgs!(fn, fn_t)) { 80 82 pragma(msg, "def: " ~ name); 81 83 void def() { trunk/infrastructure/pyd/dg_convert.d
r25 r40 28 28 module pyd.dg_convert; 29 29 30 private import pyd.ftype;30 private import meta.FuncMeta; 31 31 32 32 template 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 } 35 40 36 41 static if (ARGS == 0) { 37 alias Ret Typedelegate() type;42 alias Ret delegate() type; 38 43 } else static if (ARGS == 1) { 39 alias Ret Type delegate(ArgType!(Fn, 1)) type;44 alias Ret delegate(A!(0)) type; 40 45 } else static if (ARGS == 2) { 41 alias Ret Type delegate(ArgType!(Fn, 1), ArgType!(Fn, 2)) type;46 alias Ret delegate(A!(0), A!(1)) type; 42 47 } else static if (ARGS == 3) { 43 alias Ret Type delegate(ArgType!(Fn, 1), ArgType!(Fn, 2), ArgType!(Fn, 3)) type;48 alias Ret delegate(A!(0), A!(1), A!(2)) type; 44 49 } else static if (ARGS == 4) { 45 alias Ret Type 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; 46 51 } else static if (ARGS == 5) { 47 alias Ret Type 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; 48 53 } else static if (ARGS == 6) { 49 alias Ret Type 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; 50 55 } else static if (ARGS == 7) { 51 alias Ret Type 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; 52 57 } else static if (ARGS == 8) { 53 alias Ret Type 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; 54 59 } else static if (ARGS == 9) { 55 alias Ret Type 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; 56 61 } else static if (ARGS == 10) { 57 alias Ret Type 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; 58 63 } 59 64 } … … 89 94 return u.real_dg; 90 95 } 96 trunk/infrastructure/pyd/func_wrap.d
r37 r40 22 22 module pyd.func_wrap; 23 23 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; 24 private { 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 } 34 41 35 42 // Builds a Python callable object from a delegate or function pointer. 36 template DPyFunc_FromDG(T , uint MIN_ARGS=NumberOfArgs!(T)) {43 template DPyFunc_FromDG(T) { 37 44 PyObject* DPyFunc_FromDG(T dg) { 38 45 alias wrapped_class_type!(T) type; … … 54 61 } 55 62 63 // Populates the tuple t with converted arguments from the PyTuple args 64 private 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 71 private 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 56 80 // 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; 81 RetType!(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; 60 85 61 86 int ARGS = 0; … … 63 88 if (args !is null) { 64 89 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"); 66 91 } 67 92 68 93 // Sanity check! 69 94 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); 76 96 handle_exception(); 77 97 } 78 98 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); 108 106 return; 109 107 } else { 110 return apply _tuple_to_fn(t, fn);108 return apply(fn, t); 111 109 } 112 110 } 113 111 114 112 template 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; 117 116 // The entry for the tp_call slot of the DPyFunc types. 118 117 // (Or: What gets called when you pass a delegate or function pointer to … … 129 128 130 129 return exception_catcher({ 131 static if (is(R etType== void)) {130 static if (is(RT == void)) { 132 131 py_call(fn, args); 133 132 Py_INCREF(Py_None); … … 143 142 // with a PyCFunction. 144 143 template 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; 147 147 148 148 // Wraps py_call to return a PyObject* 149 149 PyObject* py_py_call(fn_t, PY)(fn_t fn, PY* args) { 150 static if (is(Ret urnType!(fn_t) == void)) {150 static if (is(RetType!(fn_t) == void)) { 151 151 py_call(fn, args); 152 152 Py_INCREF(Py_None); … … 157 157 } 158 158 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 159 177 // Calls py_py_call with the proper function contained in a tuple 160 178 // returned from tuples.func_range. 161 179 PyObject* tuple_py_call(Tu, PY)(Tu t, PY* args) { 162 int ARGS= 0;180 int argCount = 0; 163 181 if (args !is null) 164 ARGS = PyObject_Length(args); 182 argCount = PyObject_Length(args); 183 165 184 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); 201 189 } 202 190 … … 207 195 return exception_catcher(delegate PyObject*() { 208 196 // 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 inreal_fn197 // the object in self and turn the member function alias real_fn 210 198 // into a delegate. This conversion is done with a dirty hack; see 211 199 // dg_convert.d. … … 219 207 C instance = (cast(wrapped_class_object!(C)*)self).d_obj; 220 208 fn_to_dg!(fn_t) fn = dg_wrapper!(C, fn_t)(instance, &real_fn); 221 static if (is(Ret urnType!(typeof(fn)) == void)) {209 static if (is(RetType!(typeof(fn)) == void)) { 222 210 py_call(fn, args); 223 211 Py_INCREF(Py_None); … … 228 216 // If C is not specified, then this is just a normal function call. 229 217 } 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); 231 219 } 232 220 }); … … 252 240 253 241 Dg 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 245 private 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 } 284 282 285 283 private … … 297 295 298 296 Tr fn(Tr)() { 299 return boilerplate!(Tr)(call( ));297 return boilerplate!(Tr)(call(makeTuple())); 300 298 } 301 299 302 300 Tr fn(Tr, T1)(T1 t1) { 303 return boilerplate!(Tr)(call( t1));301 return boilerplate!(Tr)(call(makeTuple(t1))); 304 302 } 305 303 306 304 Tr fn(Tr, T1, T2)(T1 t1, T2 t2) { 307 return boilerplate!(Tr)(call( t1, t2));305 return boilerplate!(Tr)(call(makeTuple(t1, t2))); 308 306 } 309 307 310 308 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))); 312 310 } 313 311 314 312 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))); 316 314 } 317 315 318 316 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))); 320 318 } 321 319 322 320 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))); 324 322 } 325 323 326 324 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))); 328 326 } 329 327 330 328 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))); 332 330 } 333 331 334 332 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))); 336 334 } 337 335 338 336 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
