Changeset 41

Show
Ignore:
Timestamp:
10/26/06 18:10:53 (2 years ago)
Author:
KirkMcDonald
Message:

Doc updates; some cleanup; op_wrap additions

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/examples/testdll/testdll.d

    r40 r41  
    106106extern (C) 
    107107export void inittestdll() { 
    108     def!(foo/*, "foo"*/); 
     108    def!(foo); 
    109109    // Python does not support function overloading. This allows us to wrap 
    110110    // an overloading function under a different name. Note that if the 
     
    112112    // must be specified. 
    113113    def!(foo, "foo2", void function(int), 1); 
    114     def!(bar, "bar"); 
     114    def!(bar); 
    115115    // Default argument support - Now implicit! 
    116     def!(baz, "baz"); 
    117     def!(spam, "spam"); 
    118     def!(iter_test, "iter_test"); 
    119     def!(func_test, "func_test"); 
    120     def!(dg_test, "dg_test"); 
     116    def!(baz); 
     117    def!(spam); 
     118    def!(iter_test); 
     119    def!(func_test); 
     120    def!(dg_test); 
    121121 
    122122    module_init("testdll"); 
    123123 
    124     auto t = func_range!(foo, 0)(); 
    125     alias typeof(t) Tu; 
    126     writefln(typeid(TypeNo!(Tu, 1))); 
    127     writefln(MIN_ARGS!(bar)); 
    128  
    129     wrapped_class!(Foo, "Foo") f; 
     124    wrapped_class!(Foo) f; 
    130125    // Constructor wrapping 
    131126    f.init!(void function(int), void function(int, int)); 
    132127    // Member function wrapping 
    133     f.def!(Foo.foo, "foo"); 
     128    f.def!(Foo.foo); 
    134129    // Property wrapping 
    135     f.prop!(Foo.i, "i"); 
     130    f.prop!(Foo.i); 
    136131    finalize_class(f); 
    137132} 
  • trunk/html_doc/class_wrapping.html

    r38 r41  
    2626<p>Exposing D classes to Python is easy! The heart of Pyd's class wrapping features is the <code>wrapped_class</code> template struct:</p> 
    2727 
    28 <p><code>struct wrapped_class(<span class="t_arg">T</span>, char[] <span class="t_arg">classname</span>);</code></p> 
     28<p><code>struct wrapped_class(<span class="t_arg">T</span>, char[] <span class="t_arg">classname</span> = symbolnameof!(T));</code></p> 
    2929    <ul> 
    3030    <li><span class="t_arg">T</span> is the class being wrapped.</li> 
     
    3535 
    3636<dl> 
    37 <dt><code>static void def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span>, <span class="t_arg">fn_t</span> = typeof(&amp;fn)) ();</code></dt> 
     37<dt><code>static void 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(&amp;fn)) ();</code></dt> 
    3838<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> 
    3939 
     
    4242    <ul> 
    4343    <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> 
    44     <li><span class="t_arg">name</span> is the name of the property as it will appear in Python.</li> 
     44    <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> 
    4545    <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> 
    4646    </ul> 
     
    4848 
    4949<dt><code>static void init(<span class="t_arg">C1</span>, <span class="t_arg">C2</span>, <span class="t_arg">C3</span>, ..., <span class="t_arg">C<i>n</i></span>) ();</code></dt> 
    50 <dd>This allows you to expose anywhere from zero to 10 of the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each of <span class="t_arg">C<i>n</i></span> should be an instance of the <code>pyd.tuples.tuple</code> template (not an instance of the tuple struct <em>itself</em>, but an instance of the <em>template</em>), which in turn supports up to 10 arguments. Each tuple should correspond to a constructor. There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd> 
     50<dd>This allows you to expose anywhere from zero to 10 of the class's constructors to Python. If the class provides a zero-argument constructor, there is no need to specify it; it is always available. Each of <span class="t_arg">C<i>n</i></span> should be a function type. Each function type should correspond to a constructor. (That is, the arguments to the function should be the same as arguments to the class constructor. The return type is ignored.) There is an additional limitation at this time: No two constructors may have the same number of arguments. Pyd will always attempt to call the first constructor with the right number of arguments. If you wish to support a constructor with default arguments, you must specify each possible constructor call as a different template argument to this function. The examples show a few uses of the <code>init</code> function.</dd> 
     51 
     52<dt><code>static void iter(<span class="t_arg">iter_t</span>) ();</code></dt> 
     53<dd>This allows the user to specify a different overload of opApply than the default. (The default is always the one that is lexically first.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate that forms the argument to opApply. This might be e.g. <code>int delegate(inout int)</code>. Don't forget the <code>inout</code> modifiers!</dd> 
     54 
     55<dt><code>static void alt_iter(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), iter_t = <i>implementationDetail</i>) ();</code></dt> 
     56<dd>This wraps alternate iterator methods as Python methods that return iterator objects. The wrapped methods should have a signature like that of opApply. (In other words, they should be methods intended to be used with D's ability to iterate over delgates.) The <span class="t_arg">iter_t</span> argument should be the type of the delegate argument to the method. This will usually be derived automatically. 
     57</dd> 
    5158</dl> 
    5259 
     
    7481<p>At the moment, only the following operator overloads are supported:</p> 
    7582 
    76 <p><code>opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opApply</code></p> 
     83<p><code>opAdd, opSub, opMul, opDiv, opMod, opAnd, opOr, opXor, opShl, opShr, opCat, opAddAssign, opSubAssign, opMulAssign, opDivAssign, opModAssign, opAndAssign, opOrAssign, opXorAssign, opShlAssign, opShrAssign, opCatAssign, opIn_r, opCmp, opCall, opApply</code></p> 
    7784 
    78 <p>Most notably missing from this list are <code>opIndex, opIndexAssign, opSlice, opSliceAssign</code>, and <code>opCall</code>. Support for these operators is forthcoming. Also missing from the 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.)</p> 
     85<p>Most notably missing from this list are <code>opIndex, opIndexAssign, opSlice</code>, and <code>opSliceAssign</code>. Support for these operators is forthcoming. Also missing from the 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>alt_iter</code>.</p> 
     86 
     87<!-- This is not yet implemented. 
     88<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>. You may still wrap it with <code>prop</code> if you wish it to be available as a normal property.</p> 
     89--> 
    7990 
    8091<p>Notably <em>included</em> in the list is <code>opApply</code>. Pyd wraps D's iteration protocol with the help of Mikola Lysenko's StackThreads package.</p> 
     
    108119 
    109120<pre class="code"><span class="comment">// Make an instance of wrapped_class</span> 
    110 wrapped_class!(Foo, <span class="string">"Foo"</span>) f; 
     121wrapped_class!(Foo) f; 
    111122<span class="comment">// Wrap the "foo" method</span> 
    112 f.def!(Foo.foo, <span class="string">"foo"</span>); 
     123f.def!(Foo.foo); 
    113124<span class="comment">// Wrap the "i" property</span> 
    114 f.prop!(Foo.i, <span class="string">"i"</span>); 
     125f.prop!(Foo.i); 
    115126<span class="comment">// Wrap the constructors.</span> 
    116 f.init!(tuple!(<span class="keyword">int</span>), tuple!(<span class="keyword">int</span>, <span class="keyword">int</span>)); 
     127f.init!(<span class="keyword">void function</span>(<span class="keyword">int</span>), <span class="keyword">void function</span>(<span class="keyword">int</span>, <span class="keyword">int</span>)); 
    117128finalize_class(f);</pre> 
    118129 
  • trunk/html_doc/func_wrapping.html

    r35 r41  
    2626<p>Exposing D functions to Python is easy! The heart of Pyd's function wrapping features is the <code>def</code> template function:</p> 
    2727 
    28 <p><code>void def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span>, <span class="t_arg">fn_t</span> = typeof(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = MIN_ARGS!(fn)) ();</code></p> 
     28<p><code>void 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(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn)) ();</code></p> 
    2929    <ul> 
    3030    <li><span class="t_arg">fn</span> is the function to wrap. Note that this is an alias parameter. <code>def</code> is only capable of wrapping full-fledged functions, not function pointers, function literals, or delegates.</li> 
    31     <li><span class="t_arg">name</span> is the name the function will have inside of Python.</li> 
     31    <li><span class="t_arg">name</span> is the name the function will have inside of Python. Usually, you don't have to specify this. (Special thanks to Don Clugston's Nameof module.)</li> 
    3232    <li><span class="t_arg">fn_t</span> is the function type of the function. Typically, you won't have to specify this. It is used to wrap overloaded functions. (See below.)</li> 
    33     <li><span class="t_arg">MIN_ARGS</span> is the minimum number of arguments this function can accept. It is used when a function has default arguments. The <code>MIN_ARGS</code> template can derive the correct number automatically, so you typically won't specify this manually.</li> 
     33    <li><span class="t_arg">MIN_ARGS</span> is the minimum number of arguments this function can accept. It is used when a function has default arguments. The <code>minArgs</code> template can derive the correct number automatically, so you typically won't specify this manually.</li> 
    3434    </ul> 
    3535 
    36 <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">convertable</a> can be wrapped by <code>def</code>. <code>def</code> also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:</p> 
     36<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">convertable</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> 
    3737 
    3838<pre class="code"><span class="keyword">import</span> pyd.pyd; 
     
    5858<span class="keyword">export void</span> inittestmodule() { 
    5959    <span class="comment">// Plain old function</span> 
    60     def!(foo, <span class="string">"foo"</span>); 
    61     <span class="comment">// Wraps the lexically first function</span> 
     60    def!(foo); 
     61    <span class="comment">// Wraps the lexically first function under the given name</span> 
    6262    def!(bar, <span class="string">"bar1"</span>); 
    6363    <span class="comment">// Wraps the function of the specified type</span> 
    6464    def!(bar, <span class="string">"bar2"</span>, <span class="keyword">void function</span>(<span class="keyword">char</span>[])); 
    6565    <span class="comment">// Wraps the function with default arguments</span> 
    66     def!(baz, <span class="string">"baz"</span>); 
     66    def!(baz); 
    6767 
    6868    module_init(<span class="string">"testmodule"</span>); 
  • trunk/infrastructure/pyd/class_wrap.d

    r40 r41  
    3636    import meta.FuncMeta; 
    3737    import meta.Tuple; 
     38    import meta.Nameof; 
    3839 
    3940    import std.string; 
     
    8384        Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ 
    8485        null,                         /*tp_doc*/ 
    85         null,                    /* tp_traverse */ 
    86         null,                    /* tp_clear */ 
    87         null,                    /* tp_richcompare */ 
    88         0,                   /* tp_weaklistoffset */ 
    89         null,                    /* tp_iter */ 
    90         null,                    /* tp_iternext */ 
     86        null,                         /* tp_traverse */ 
     87        null,                         /* tp_clear */ 
     88        null,                         /* tp_richcompare */ 
     89        0,                            /* tp_weaklistoffset */ 
     90        null,                         /* tp_iter */ 
     91        null,                         /* tp_iternext */ 
    9192        null,                         /* tp_methods */ 
    9293        null,                         /* tp_members */ 
     
    248249 * wrapping the specific parts of the class. 
    249250 */ 
    250 template wrapped_class(T, char[] classname) { 
     251template wrapped_class(T, char[] classname = symbolnameof!(T)) { 
    251252    pragma(msg, "wrapped_class: " ~ classname); 
    252253    struct wrapped_class { 
     
    287288         * RO = Whether this is a read-only property. 
    288289         */ 
    289         template prop(alias fn, char[] name, bool RO=false) { 
     290        template prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) { 
    290291            pragma(msg, "class.prop: " ~ name); 
    291292            static void prop() { 
     
    376377    type.tp_methods   = wrapped_method_list!(T); 
    377378    type.tp_name      = module_name ~ "." ~ name ~ \0; 
     379 
     380    // Numerical operator overloads 
    378381    if (wrapped_class_as_number!(T) != PyNumberMethods.init) { 
    379382        type.tp_as_number = &wrapped_class_as_number!(T); 
    380383    } 
    381  
     384    // Sequence operator overloads 
     385    if (wrapped_class_as_sequence!(T) != PySequenceMethods.init) { 
     386        type.tp_as_sequence = &wrapped_class_as_sequence!(T); 
     387    } 
     388    // Mapping operator overloads 
     389    if (wrapped_class_as_mapping!(T) != PyMappingMethods.init) { 
     390        type.tp_as_mapping = &wrapped_class_as_mapping!(T); 
     391    } 
     392 
     393    // Standard operator overloads 
     394    // opApply 
    382395    static if (is(typeof(&T.opApply))) { 
    383396        if (type.tp_iter is null) { 
     
    386399        } 
    387400    } 
    388      
     401    // opCmp 
     402    static if (is(typeof(&T.opCmp))) { 
     403        type.tp_compare = &opcmp_wrap!(T).func; 
     404    } 
     405    // opCall 
     406    static if (is(typeof(&T.opCall))) { 
     407        type.tp_call = cast(ternaryfunc)&func_wrap!(T.opCall, minArgs!(T.opCall), T).func; 
     408    } 
     409 
    389410    // If a ctor wasn't supplied, try the default. 
    390411    if (type.tp_init is null) { 
  • trunk/infrastructure/pyd/op_wrap.d

    r37 r41  
    2626private import pyd.class_wrap; 
    2727private import pyd.func_wrap; 
     28private import pyd.exception; 
     29private import pyd.make_object; 
     30 
     31private import meta.FuncMeta; 
    2832 
    2933template wrapped_class_as_number(T) { 
     
    7377    static PySequenceMethods wrapped_class_as_sequence = { 
    7478        null,                 /*sq_length*/ 
    75         null,                 /*sq_concat*/ 
     79        opCat_wrap!(T),       /*sq_concat*/ 
    7680        null,                 /*sq_repeat*/ 
    7781        null,                 /*sq_item*/ 
     
    8084        null,                 /*sq_ass_slice*/ 
    8185        null,                 /*sq_contains*/ 
    82         null,                /*sq_inplace_concat*/ 
     86        opCatAssign_wrap!(T), /*sq_inplace_concat*/ 
    8387        null,                 /*sq_inplace_repeat*/ 
    8488    }; 
     
    115119} 
    116120 
     121template opindex_sequence_pyfunc(T) { 
     122    alias wrapped_class_object!(T) wrap_object; 
     123     
     124    extern(C) 
     125    PyObject* func(PyObject* self, int i) { 
     126        return exception_catcher(delegate PyObject*() { 
     127            return _py((cast(wrap_object*)self).d_obj.opIndex(i)); 
     128        }); 
     129    } 
     130} 
     131 
     132template opindexassign_sequence_pyfunc(T) { 
     133    alias wrapped_class_object!(T) wrap_object; 
     134 
     135    extern(C) 
     136    int func(PyObject* self, int i, PyObject* o) { 
     137         
     138    } 
     139} 
     140 
     141template opcmp_wrap(T) { 
     142    alias wrapped_class_object!(T) wrap_object; 
     143    alias funcDelegInfoT!(typeof(&T.opCmp)) Info; 
     144    alias Info.Meta.ArgType!(0) OtherT; 
     145    extern(C) 
     146    int func(PyObject* self, PyObject* other) { 
     147        return exception_catcher(delegate int() { 
     148            int result = (cast(wrap_object*)self).d_obj.opCmp(d_type!(OtherT)(other)); 
     149            // The Python API reference specifies that tp_compare must return 
     150            // -1, 0, or 1. The D spec says opCmp may return any integer value, 
     151            // and just compares it with zero. 
     152            if (result < 0) return -1; 
     153            if (result == 0) return 0; 
     154            if (result > 0) return 1; 
     155        }); 
     156    } 
     157} 
     158 
     159// The rest of the file is composed of these short stubs 
     160template opIndex_sequence_wrap(T) { 
     161    static if (is(typeof(&T.opIndex)) && 
     162               funcDelegInfoT!(typeof(&T.opIndex)).numArgs == 1 && 
     163               is(funcDelegInfoT!(typeof(&T.opIndex)).Meta.ArgType!(0) : int) 
     164    ) { 
     165        const intargfunc opIndex_sequence_wrap = &opindex_sequence_pyfunc!(T).func; 
     166    } else { 
     167        const intargfunc opIndex_sequence_wrap = null; 
     168    } 
     169} 
     170 
     171template opIndexAssign_sequence_wrap(T) { 
     172    static if (true) { 
     173        const intobjargproc opIndexAssign_sequence_wrap = null; 
     174    } else { 
     175        const intobjargproc opIndexAssign_sequence_wrap = null; 
     176    } 
     177} 
     178 
     179template opIndex_mapping_wrap(T) { 
     180 
     181} 
     182 
     183template opIndexAssign_mapping_wrap(T) { 
     184 
     185} 
     186 
     187template opSlice_wrap(T) { 
     188 
     189} 
     190 
     191template opSliceAssign_wrap(T) { 
     192 
     193} 
     194 
    117195template opAdd_wrap(T) { 
    118196    static if (is(typeof(&T.opAdd))) { 
  • trunk/infrastructure/pyd/pyd.d

    r29 r41  
    3232public import pyd.dpyobject; 
    3333public import pyd.exception; 
    34 public import pyd.ftype; 
    3534public import pyd.func_wrap; 
    3635public import pyd.make_object; 
    37 public import pyd.tuples; 
    3836