Changeset 40
- Timestamp:
- 10/24/06 01:24:13 (6 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 else static if (!is(T4 == Dummy)) 357 const uint ARGS = 4; 358 else static if (!is(T3 == Dummy)) 359 const uint ARGS = 3; 360 else static if (!is(T2 == Dummy)) 361 const uint ARGS = 2; 362 else static if (!is(T1 == Dummy)) 363 const uint ARGS = 1; 364 else 365 const uint ARGS = 0; 366 PyObject* t = PyTuple_New(ARGS); 367 if (t is null) return null; 368 scope(exit) Py_DECREF(t); 369 static if (!is(T10 == Dummy)) 370 PyTuple_SetItem(t, 9, _py(t10)); 371 static if (!is(T9 == Dummy)) 372 PyTuple_SetItem(t, 8, _py(t9)); 373 static if (!is(T8 == Dummy)) 374 PyTuple_SetItem(t, 7, _py(t8)); 375 static if (!is(T7 == Dummy)) 376 PyTuple_SetItem(t, 6, _py(t7)); 377 static if (!is(T6 == Dummy)) 378 PyTuple_SetItem(t, 5, _py(t6)); 379 static if (!is(T5 == Dummy)) 380 PyTuple_SetItem(t, 4, _py(t5)); 381 static if (!is(T4 == Dummy)) 382 PyTuple_SetItem(t, 3, _py(t4)); 383 static if (!is(T3 == Dummy)) 384 PyTuple_SetItem(t, 2, _py(t3)); 385 static if (!is(T2 == Dummy)) 386 PyTuple_SetItem(t, 1, _py(t2)); 387 static if (!is(T1 == Dummy)) 388 PyTuple_SetItem(t, 0, _py(t1)); 389 return PyObject_CallObject(callable, t); 390 } 391 } 392 } 337 return boilerplate!(Tr)(call(makeTuple(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10))); 338 } 339 340 void loop(T, uint current)(T* dt, PyObject* pyt) { 341 static if (current < T.length) { 342 PyTuple_SetItem(pyt, current, _py(dt.val!(current))); 343 loop!(T, current+1)(dt, pyt); 344 } 345 } 346 347 PyObject* call(T) (T dt) { 348 const uint ARGS = T.length; 349 350 PyObject* pyt = PyTuple_New(ARGS); 351 if (pyt is null) return null; 352 scope(exit) Py_DECREF(pyt); 353 354 loop!(T, 0)(&dt, pyt); 355 return PyObject_CallObject(callable, pyt); 356 } 357 } trunk/infrastructure/pyd/generators/min_args.py
r26 r40 3 3 sys.stdout = open('min_args.txt', 'w') 4 4 5 arg_template = """ ArgType!(fn_t, %s).init"""5 arg_template = """I!(%s)()""" 6 6 7 7 template = """\ 8 else static if (is(typeof(fn(%s))))9 const uint MIN_ARGS= %s;"""8 \telse static if (is(typeof(fn(%s)))) 9 \t\tconst uint minArgs = %s;""" 10 10 11 for i in range( 1, 11):11 for i in range(21): 12 12 args = [] 13 13 for j in range(i): 14 args.append(arg_template % (j +1,))14 args.append(arg_template % (j,)) 15 15 print template % (", ".join(args), i) 16 17 sys.stdout = old_stdout 18 trunk/infrastructure/pyd/generators/min_args.txt
r26 r40 1 else static if (is(typeof(fn(ArgType!(fn_t, 1).init)))) 2 const uint MIN_ARGS = 1; 3 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init)))) 4 const uint MIN_ARGS = 2; 5 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init)))) 6 const uint MIN_ARGS = 3; 7 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init)))) 8 const uint MIN_ARGS = 4; 9 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init)))) 10 const uint MIN_ARGS = 5; 11 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init)))) 12 const uint MIN_ARGS = 6; 13 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init)))) 14 const uint MIN_ARGS = 7; 15 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init)))) 16 const uint MIN_ARGS = 8; 17 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init, ArgType!(fn_t, 9).init)))) 18 const uint MIN_ARGS = 9; 19 else static if (is(typeof(fn(ArgType!(fn_t, 1).init, ArgType!(fn_t, 2).init, ArgType!(fn_t, 3).init, ArgType!(fn_t, 4).init, ArgType!(fn_t, 5).init, ArgType!(fn_t, 6).init, ArgType!(fn_t, 7).init, ArgType!(fn_t, 8).init, ArgType!(fn_t, 9).init, ArgType!(fn_t, 10).init)))) 20 const uint MIN_ARGS = 10; 1 else static if (is(typeof(fn()))) 2 const uint minArgs = 0; 3 else static if (is(typeof(fn(I!(0)())))) 4 const uint minArgs = 1; 5 else static if (is(typeof(fn(I!(0)(), I!(1)())))) 6 const uint minArgs = 2; 7 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)())))) 8 const uint minArgs = 3; 9 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)())))) 10 const uint minArgs = 4; 11 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)())))) 12 const uint minArgs = 5; 13 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)())))) 14 const uint minArgs = 6; 15 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)())))) 16 const uint minArgs = 7; 17 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)())))) 18 const uint minArgs = 8; 19 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)())))) 20 const uint minArgs = 9; 21 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)())))) 22 const uint minArgs = 10; 23 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)())))) 24 const uint minArgs = 11; 25 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)())))) 26 const uint minArgs = 12; 27 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)())))) 28 const uint minArgs = 13; 29 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)())))) 30 const uint minArgs = 14; 31 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)())))) 32 const uint minArgs = 15; 33 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)(), I!(15)())))) 34 const uint minArgs = 16; 35 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)(), I!(15)(), I!(16)())))) 36 const uint minArgs = 17; 37 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)(), I!(15)(), I!(16)(), I!(17)())))) 38 const uint minArgs = 18; 39 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)(), I!(15)(), I!(16)(), I!(17)(), I!(18)())))) 40 const uint minArgs = 19; 41 else static if (is(typeof(fn(I!(0)(), I!(1)(), I!(2)(), I!(3)(), I!(4)(), I!(5)(), I!(6)(), I!(7)(), I!(8)(), I!(9)(), I!(10)(), I!(11)(), I!(12)(), I!(13)(), I!(14)(), I!(15)(), I!(16)(), I!(17)(), I!(18)(), I!(19)())))) 42 const uint minArgs = 20; trunk/infrastructure/pyd/iteration.d
r39 r40 29 29 private import python; 30 30 private import pyd.class_wrap; 31 private import pyd.dg_convert; 31 32 private import pyd.exception; 32 private import pyd.ftype;33 //private import pyd.ftype; 33 34 private import pyd.make_object; 35 36 private import meta.FuncMeta; 37 34 38 private import st.stackcontext; 35 39 … … 60 64 61 65 // Creates an iterator object from an object. 62 PyObject* DPySC_FromWrapped(T ) (T obj) {66 PyObject* DPySC_FromWrapped(T, alias Iter = T.opApply, iter_t = typeof(&Iter)) (T obj) { 63 67 // Get the number of args the opApply's delegate argument takes 64 const uint ARGS = NumberOfArgsInout!(ArgType!(typeof(&T.opApply), 1)); 68 alias funcDelegInfoT!(iter_t) IInfo; 69 alias funcDelegInoutInfoT!(IInfo.Meta.ArgType!(0)) Info; 70 const uint ARGS = Info.numArgs; 65 71 auto sc = new StackContext(delegate void() { 66 T t = obj; 72 T o = obj; 73 fn_to_dg!(iter_t) t = dg_wrapper!(T, iter_t)(o, &Iter); 67 74 // So we can get the variable in the enclosing function's stack frame 68 75 StackContext.yield(); … … 135 142 } 136 143 137 template wrapped_iter(T ) {144 template wrapped_iter(T, alias Iter, iter_t = typeof(&Iter)) { 138 145 alias wrapped_class_object!(T) wrap_object; 139 146 … … 144 151 wrap_object* self = cast(wrap_object*)_self; 145 152 146 return DPySC_FromWrapped (self.d_obj);153 return DPySC_FromWrapped!(T, Iter, iter_t)(self.d_obj); 147 154 }); 148 155 } trunk/infrastructure/st/stackcontext.d
r37 r40 19 19 * implementations. 20 20 * 21 * Version: 0.1 022 * Date: June 30, 200621 * Version: 0.12 22 * Date: October 17, 2006 23 23 * Authors: Mikola Lysenko, mclysenk@mtu.edu 24 24 * License: Use/copy/modify freely, just give credit. … … 31 31 * since overflows are now trapped. 32 32 * 33 * Implementation is not thread safe.34 *35 33 * DMD has a bug on linux with multiple delegates in a 36 34 * scope. Be aware that the linux version may have … … 48 46 * removeRange I have set it as optional. 49 47 * 48 * GDC version does not support assembler optimizations, since 49 * it uses a different calling convention. 50 * 50 51 * History: 52 * v0.12 - Workaround for DMD bug. 53 * 54 * v0.11 - Implementation is now thread safe. 55 * 51 56 * v0.10 - Added the LEAK_FIX flag to work around the 52 57 * slowness of std.gc.removeRange … … 81 86 std.stdio, 82 87 std.string, 83 std.gc; 88 std.gc, 89 st.tls; 90 91 //Handle versions 92 version(D_InlineAsm_X86) 93 { 94 version(DigitalMars) 95 { 96 version(Win32) version = SC_WIN_ASM; 97 version(linux) version = SC_LIN_ASM; 98 } 99 100 //GDC uses a different calling conventions, need to reverse engineer them later 101 } 102 84 103 85 104 /// The default size of a StackContext's stack … … 136 155 } 137 156 } 157 158 138 159 139 160 … … 255 276 * 256 277 ******************************************************/ 257 public class StackContext278 public final class StackContext 258 279 { 259 280 /** … … 335 356 { 336 357 assert(state != CONTEXT_STATE.RUNNING); 337 assert(current_context !is this);358 assert(current_context.val !is this); 338 359 } 339 360 body … … 357 378 * bubbled up through this method. 358 379 */ 359 public void run()380 public final void run() 360 381 { 361 382 debug (StackContext) writefln("Running %s", this.toString); 362 383 363 384 //We must be ready to run 364 if(state != CONTEXT_STATE.READY) 365 { 366 throw new ContextException(this, 367 "Context is not in a runnable state"); 368 } 385 assert(state == CONTEXT_STATE.READY, 386 "Context is not in a runnable state"); 369 387 370 388 //Save the old context 371 StackContext tmp = current_context ;389 StackContext tmp = current_context.val; 372 390 373 391 version(LEAK_FIX) … … 379 397 380 398 //Set new context 381 current_context = this;399 current_context.val = this; 382 400 ctx.switchIn(); 383 current_context = tmp;401 current_context.val = tmp; 384 402 385 403 assert(state != CONTEXT_STATE.RUNNING); … … 428 446 * running context. 429 447 */ 430 public static void yield() 431 { 432 if(current_context is null) 433 { 434 throw new ContextException( 435 null, 436 "Tried to yield without any running contexts."); 437 } 438 439 debug (StackContext) writefln("Yielding %s", current_context.toString); 440 441 assert(current_context.running); 448 public final static void yield() 449 { 450 StackContext cur_ctx = current_context.val; 451 452 //Make sure we are actually running 453 assert(cur_ctx !is null, 454 "Tried to yield without any running contexts."); 455 456 debug (StackContext) writefln("Yielding %s", cur_ctx.toString); 457 458 assert(cur_ctx.running); 442 459 443 460 //Leave the current context 444 cur rent_context.state = CONTEXT_STATE.READY;445 StackContext tmp = cur rent_context;461 cur_ctx.state = CONTEXT_STATE.READY; 462 StackContext tmp = cur_ctx; 446 463 447 464 version(LEAK_FIX) 448 465 { 449 466 //Save the GC range 450 cur rent_context.gc_start = cast(void*)&tmp;467 cur_ctx.gc_start = cast(void*)&tmp; 451 468 debug (LogGC) writefln("Adding range: %8x-%8x", 452 cur rent_context.gc_start, current_context.ctx.stack_top);453 addRange(cur rent_context.gc_start, current_context.ctx.stack_top);469 cur_ctx.gc_start, cur_ctx.ctx.stack_top); 470 addRange(cur_ctx.gc_start, cur_ctx.ctx.stack_top); 454 471 } 455 472 456 473 //Swap 457 cur rent_context.ctx.switchOut();474 cur_ctx.ctx.switchOut(); 458 475 459 476 version(LEAK_FIX) 460 477 { 478 StackContext t_ctx = current_context.val; 479 461 480 //Remove the GC range 462 481 debug (LogGC) writefln("Removing range: %8x", 463 current_context.gc_start);464 assert( current_context.gc_start !is null);465 removeRange( current_context.gc_start);466 current_context.gc_start = null;482 t_ctx.gc_start); 483 assert(t_ctx.gc_start !is null); 484 removeRange(t_ctx.gc_start); 485 t_ctx.gc_start = null; 467 486 } 468 487 469 488 //Return 470 current_context = tmp;471 current_context.state = CONTEXT_STATE.RUNNING;472 473 debug (StackContext) writefln("Resuming context: %s", current_context.toString);489 current_context.val = tmp; 490 tmp.state = CONTEXT_STATE.RUNNING; 491 492 debug (StackContext) writefln("Resuming context: %s", tmp.toString); 474 493 } 475 494 … … 484 503 * t = The exception object we will propagate. 485 504 */ 486 public static void throwYield(Object t)487 { 488 last_exception = t;505 public final static void throwYield(Object t) 506 { 507 current_context.val.last_exception = t; 489 508 yield(); 490 509 } … … 496 515 * A ContextException if the context is running. 497 516 */ 498 public void restart()517 public final void restart() 499 518 { 500 519 debug (StackContext) writefln("Restarting %s", this.toString); 501 520 502 if(state == CONTEXT_STATE.RUNNING) 503 { 504 throw new ContextException(this, 505 "Cannot reset this context while it is running!"); 506 } 521 assert(state != CONTEXT_STATE.RUNNING, 522 "Cannot restart a context while it is running"); 507 523 508 524 //Reset the context 525 restartStack(); 526 } 527 528 /** 529 * Recycles the context by restarting it with a new delegate. This 530 * can save resources by allowing a program to reuse previously 531 * allocated contexts. 532 * 533 * Params: 534 * dg = The delegate which we will be running. 535 */ 536 public final void recycle(void delegate() dg) 537 { 538 debug (StackContext) writefln("Recycling %s", this.toString); 539 540 assert(state != CONTEXT_STATE.RUNNING, 541 "Cannot recycle a context while it is running"); 542 543 //Set the delegate and restart 544 proc = dg; 509 545 restartStack(); 510 546 } … … 519 555 * A ContextException if the context is not READY. 520 556 */ 521 public void kill() 522 { 523 if(state == CONTEXT_STATE.RUNNING) 524 { 525 throw new ContextException(this, "Cannot kill a context if it is not ready"); 526 } 527 else if(state == CONTEXT_STATE.DEAD) 528 { 529 return; 530 } 557 public final void kill() 558 { 559 assert(state != CONTEXT_STATE.RUNNING, 560 "Cannot kill a context while it is running."); 561 531 562 532 563 version(LEAK_FIX) 533 564 { 565 if(state == CONTEXT_STATE.DEAD) 566 { 567 return; 568 } 569 534 570 //Clear the GC ranges if necessary 535 571 if(gc_start !is null) … … 550 586 * Returns: A string describing the context. 551 587 */ 552 public char[] toString()588 public final char[] toString() 553 589 { 554 590 static char[][] state_names = … … 622 658 public static StackContext getRunning() 623 659 { 624 return current_context ;660 return current_context.val; 625 661 } 626 662 … … 633 669 //Make sure context is running 634 670 //assert(ctx.old_stack_pointer !is null); 635 assert(current_context !is null);671 assert(current_context.val !is null); 636 672 637 673 case CONTEXT_STATE.READY: … … 655 691 } 656 692 } 657 658 693 659 694 version(LEAK_FIX) 660 695 { … … 669 704 private CONTEXT_STATE state; 670 705 671 //FIXME: All static objects should be in thread local672 //storage. Not sure how to do this effectively yet.673 674 /*BEGIN TLS {*/675 676 706 // The last exception generated 677 707 private static Object last_exception = null; 678 708 709 /*BEGIN TLS {*/ 710 679 711 // The currently running stack context 680 private static StackContextcurrent_context = null;681 712 private static ThreadLocal!(StackContext) current_context = null; 713 682 714 /*} END TLS*/ 683 715 … … 767 799 in 768 800 { 769 assert(current_context !is null);801 assert(current_context.val !is null); 770 802 version(LEAK_FIX) 771 assert(current_context. gc_start is null);803 assert(current_context.val.gc_start is null); 772 804 } 773 805 body 774 806 { 807 StackContext cur_ctx = current_context.val; 808 775 809 try 776 810 { 777 811 //Set state to running, enter the context 778 cur rent_context.state = CONTEXT_STATE.RUNNING;779 debug (StackContext) writefln("Starting %s", cur rent_context.toString);780 cur rent_context.proc();781 debug (StackContext) writefln("Finished %s", cur rent_context.toString);812 cur_ctx.state = CONTEXT_STATE.RUNNING; 813 debug (StackContext) writefln("Starting %s", cur_ctx.toString); 814 cur_ctx.proc(); 815 debug (StackContext) writefln("Finished %s", cur_ctx.toString); 782 816 } 783 817 catch(Object o) 784 818 { 785 819 //Save exceptions so we can throw them later 786 debug (StackContext) writefln("Got an exception: %s, in %s", o.toString, cur rent_context.toString);787 last_exception = o;820 debug (StackContext) writefln("Got an exception: %s, in %s", o.toString, cur_ctx.toString); 821 cur_ctx.last_exception = o; 788 822 } 789 823 finally … … 791 825 //Leave the object. Don't need to worry about 792 826 //GC, since it should already be released. 793 cur rent_context.state = CONTEXT_STATE.DEAD;794 debug (StackContext) writefln("Leaving %s", cur rent_context.toString);795 cur rent_context.ctx.switchOut();827 cur_ctx.state = CONTEXT_STATE.DEAD; 828 debug (StackContext) writefln("Leaving %s", cur_ctx.toString); 829 cur_ctx.ctx.switchOut(); 796 830 } 797 831 … … 807 841 version(Win32) 808 842 { 809 if(current_context is null) 843 StackContext cur = current_context.val; 844 845 if(cur is null) 810 846 return os_query_stackBottom(); 811 847 812 return cur rent_context.ctx.stack_top;848 return cur.ctx.stack_top; 813 849 } 814 850 else … … 819 855 } 820 856 } 857 858 static this() 859 { 860 StackContext.current_context = new ThreadLocal!(StackContext); 861 862 version(SC_WIN_ASM) 863 { 864 //Get the system's page size 865 SYSTEM_INFO sys_info; 866 GetSystemInfo(&sys_info); 867 page_size = sys_info.dwPageSize; 868 } 869 } 870 821 871 822 872 /******************************************************** … … 828 878 ********************************************************/ 829 879 830 private version ( Win32)880 private version (SC_WIN_ASM) 831 881 { 832 882 … … 904 954 size_t page_size; 905 955 906 static this()907 {908 //Get the system's page size909 SYSTEM_INFO sys_info;910 GetSystemInfo(&sys_info);911 page_size = sys_info.dwPageSize;912 }913 956 914 957 private struct SysContext … … 1035 1078 void killStack() 1036 1079 { 1080 //Work around for bug in DMD 0.170 1081 if(stack_bottom is null) 1082 { 1083 debug(StackContext) 1084 writefln("WARNING!!!! Accidentally deleted a context twice"); 1085 return; 1086 } 1087 1037 1088 debug (LogStack) 1038 1089 { … … 1141 1192 } 1142 1193 } 1143 else private version( linux)1194 else private version(SC_LIN_ASM) 1144 1195 { 1145 1196 … … 1225 1276 //Initialize stack pointer 1226 1277 stack_pointer = stack_top; 1227 1228 //Initialize stack state 1229 void push(uint val) 1230 { 1231 stack_pointer -= 4; 1232 *cast(uint*)stack_pointer = val; 1233 } 1234 1235 push(cast(uint)&StackContext.startContext); //Start point 1236 push(0); //EBP 1237 push(0); //EBX 1238 push(0); //ESI 1239 push(0); //EDI 1278 1279 //Initialize stack state 1280 *cast(uint*)(stack_pointer-4) = cast(uint)&StackContext.startContext; 1281 stack_pointer -= 20; 1240 1282 } 1241 1283 … … 1245 1287 void killStack() 1246 1288 { 1289 //Make sure the GC didn't accidentally double collect us... 1290 if(stack_bottom is null) 1291 { 1292 debug(StackContext) writefln("WARNING!!! Accidentally killed stack twice"); 1293 return; 1294 } 1295 1247 1296 //Deallocate the stack 1248 1297 if(munmap(stack_bottom, (stack_top - stack_bottom))) … … 1343 1392 else 1344 1393 { 1345 //Unsupported system 1346 static assert(false, "Stack Context: System Unsupported"); 1394 static assert(false, "System currently unsupported"); 1347 1395 } 1348 1396 … … 1393 1441 assert(s1 == 0); 1394 1442 assert(a.getState == CONTEXT_STATE.DEAD); 1395 assert(b.getState == CONTEXT_STATE.READY); 1396 1397 try 1398 { 1399 a.run(); 1400 assert(false); 1401 } 1402 catch(ContextException ce) 1403 { 1404 debug writefln("Generated exception correctly"); 1405 } 1406 1443 assert(b.getState == CONTEXT_STATE.READY); 1407 1444 1408 1445 assert(b.getState == CONTEXT_STATE.READY); … … 1681 1718 } 1682 1719 1720 writefln("blah2"); 1721 1683 1722 assert(a); 1684 1723 assert(b); … … 1900 1939 delete a; 1901 1940 1902 StackContext b;1903 1904 b = new StackContext(1905 delegate void()1906 {1907 b.restart();1908 assert(false);1909 });1910 1911 try1912 {1913 b.run();1914 assert(false);1915 }1916 catch(ContextException e)1917 {1918 e.print;1919 }1920 1921 try1922 {1923 StackContext.yield();1924 assert(false);1925 }1926 catch(ContextException e)1927 {1928 e.print;1929 }1930 1941 1931 1942 writefln("Standard exceptions passed"); … … 2215 2226 } 2216 2227 2228 unittest 2229 { 2230 writefln("Testing thread safety"); 2231 2232 int x = 0, y = 0; 2233 2234 StackContext sc0 = new StackContext( 2235 { 2236 while(true) 2237 { 2238 x++; 2239 StackContext.yield; 2240 } 2241 }); 2242 2243 StackContext sc1 = new StackContext( 2244 { 2245 while(true) 2246 { 2247 y++; 2248 StackContext.yield; 2249 } 2250 }); 2251 2252 Thread t0 = new Thread( 2253 { 2254 for(int i=0; i<10000; i++) 2255 sc0.run(); 2256 2257 return 0; 2258 }); 2259 2260 Thread t1 = new Thread( 2261 { 2262 for(int i=0; i<10000; i++) 2263 sc1.run(); 2264 2265 return 0; 2266 }); 2267 2268 assert(sc0); 2269 assert(sc1); 2270 assert(t0); 2271 assert(t1); 2272 2273 t0.start; 2274 t1.start; 2275 t0.wait; 2276 t1.wait; 2277 2278 assert(x == 10000); 2279 assert(y == 10000); 2280 2281 writefln("Thread safety passed!"); 2282 } 2283 trunk/infrastructure/st/stackthread.d
r37 r40 21 21 * 22 22 * Bugs: 23 * None known yet. 23 * Not thread safe. May be changed in future versions, 24 * however this will require a radical refactoring. 24 25 * 25 26 * History: trunk/readme.txt
r24 r40 12 12 13 13 Celerid is primarily written by David Rushby, and Pyd is primarily written by 14 Kirk McDonald. 14 Kirk McDonald. Pyd uses a number of additional libraries; see credits.txt for 15 details. These libraries are contained in the "infrastructure" directory. 15 16 16 17 INSTALLATION
