1. Autogenerating wxEuphoria wrappers

I figured since I've diverged from my original topic, I'd at least give the new thread a proper title. smile

I'm writing a wrapper generator for wxEuphoria. Input function prototypes (like a .h file) and it auto-generates wrappers.

I have a couple more stupid questions. Given this prototype:

wxScrollBar(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxSB_HORIZONTAL, const wxValidator& validator = wxDefaultValidator, const wxString& name = "scrollBar")

The wrapper code generates:

object WXEUAPI new_wxScrollBar(object parms)
{
int seq_len = ((s1_ptr)SEQ_PTR(parms))->length;

intptr_t parent;
parent = (wxScrollBar*)get_int( parms, 1 );

intptr_t id;
id = (wxScrollBar*)get_int( parms, 2 );

intptr_t pos;
if (seq_len < 3)
pos = wxDefaultPosition else
pos = (wxScrollBar*)get_int( parms, 3 );

intptr_t size;
if (seq_len < 4)
size = wxDefaultSize else
size = (wxScrollBar*)get_int( parms, 4 );

??? style;
if (seq_len < 5)
style = wxSB_HORIZONTAL else
style = ???;

intptr_t validator;
if (seq_len < 6)
validator = wxDefaultValidator else
validator = (wxScrollBar*)get_int( parms, 6 );

object name;
if (seq_len < 7)
name = wxT{"scrollBar") else
name = (wxScrollBar*)get_int( parms, 7 );

wxDeRefDS( parms );
return BOX_INT( new wxScrollBar( parent, id, pos, size, style, validator, name );
}

Again, the ?? indicates where the program doesn't know how to handle a datatype. In this case, it's a long.

How should I be casting the long? And is there anything else obviously wrong with the code? I've got my doubts about the handling of the string literal.

Thanks!

- David

new topic     » topic index » view message » categorize

2. Re: Autogenerating wxEuphoria wrappers

dcuny said...

Again, the ?? indicates where the program doesn't know how to handle a datatype. In this case, it's a long.

How should I be casting the long?

If you look at the NEW_CONTROL macro, it looks like the style parameter is an intptr_t, which is what get_int() returns.

dcuny said...

And is there anything else obviously wrong with the code?

The pos and size parameters are passed as separate integers from Euphoria. Parameters 4-5 are the x/y coordinates for pos and parameters 6-7 are the width/height values for size. Also, a wxValidator is passed by value and not by pointer, but in wxEuphoria, we can only pass things by pointer, so we have to dereference to get its value. We don't really use wxValidator right now (I'm not sure if there's even wrapper code for it) but when we do, we'll either need delete the object manually with delete_instance() or provide some way to track these extra objects automatically.

dcuny said...

I've got my doubts about the handling of the string literal.

Just use get_string() to get a wxString value from a sequence. You can use the opposite get_sequence() for returning wxString values as well. Matt made all these "get" functions for easily converting to/from wx and Euphoria types.

object WXEUAPI new_wxScrollBar(object parms) 
{ 
    int seq_len = ((s1_ptr)SEQ_PTR(parms))->length; 
 
    intptr_t parent; 
    parent = (wxScrollBar*)get_int( parms, 1 ); 
 
    intptr_t id; 
    id = (wxScrollBar*)get_int( parms, 2 ); 
 
    wxString caption; 
    caption = get_string( parms, 3 ); 
 
    intptr_t pos; 
    if (seq_len < 5) 
        pos = wxDefaultPosition; 
    else 
        pos = wxPoint( get_int(parms,4), get_int(parms, 5) ); // x,y coords 
 
    intptr_t size; 
    if (seq_len < 7) 
        size = wxDefaultSize; 
    else 
        size = wxSize( get_int(parms,6), get_int(parms,7) ); // width/height 
 
    intptr_t style; 
    if (seq_len < 8) 
        style = wxSB_HORIZONTAL; // default style 
    else 
        style = get_int( parms, 8 ); 
 
    wxValidator validator; 
    if (seq_len < 9) 
        validator = wxDefaultValidator; 
    else 
        // wxValidator should be passed in as a pointer, so 
        // it needs to be dereferenced and passed by value. 
        validator = *(wxValidator*)get_int( parms, 9 ); 
 
    wxString name; 
    if (seq_len < 10) 
        name = "scrollBar"; // don't need wxT() or _T() with wxWidgets 2.9+ 
    else 
        name = get_string( parms, 10 ); 
 
    wxDeRefDS( parms ); 
 
    return BOX_INT( new wxScrollBar(parent, id, pos, size, style, validator, name) ); 
} 

-Greg

new topic     » goto parent     » topic index » view message » categorize

3. Re: Autogenerating wxEuphoria wrappers

ghaberek said...

If you look at the NEW_CONTROL macro, it looks like the style parameter is an intptr_t, which is what get_int() returns.

Hrm... Well there's a larger problem I'm trying to deal with here. How is the wrapper generator supposed to know that style is a inptr_t? Based on the prototype, it looks like it's declared as a long:

long style = wxSB_HORIZONTAL

Obviously, the code generator isn't going to be able to know to look at the NEW_CONTROL macro. blink

I'll just assume that all long datatypes can be treated like this.

ghaberek said...

The pos and size parameters are passed as separate integers from Euphoria.

But again, how does the code generator know that? The prototypes that I'm using came from the wxWidgets website. Obviously, there was a decision that wxEuphoria would have constructors that didn't match those of wxWidgets.

That's fine, but the question then becomes how the wrapper generator gets informed of this, so it can generate the proper code.

You can't just change the parameters in the prototype, because the wrapper generator still needs to construct the correct call internally.

There are a couple ways to handle this. One is to make the assumption that all constructor calls that reference wxPoint and wxSize expect an integer pair, and have it generate appropriate code.

Another option would be to manually replace wxPoint and wxSize with WXPOINT and WXSIZE to inform the wrapper generator that these are intended to be replaced. I could add a flag like this:

%expand WXPOINT wxPoint( int x, int y ) : %expand WXSIZE wxSize( int x, int y )

so you could declare additional expansions if you needed, instead of having to modify the code generator.

Thoughts?

said...

Also, a wxValidator is passed by value and not by pointer, but in wxEuphoria, we can only pass things by pointer, so we have to de-reference to get its value.

Again, this is something that can be handled fairly easily by adding a flag to the prototype.

Since wxValidator is an optional parameter, it's a non-issue in this case. For places where wxEuphoria deviates from the wxWidgets prototypes, the fallback solution would be to use the {% ... }% directives to insert the new prototype, and then some additional directive telling it to create glue for that code.

ghaberek said...

Just use get_string() to get a wxString value from a sequence.

Excellent. I think I've got the "basic prototype to C++" code working fairly well, so I'll turn my attention to handling events and constants, since the wxStyledTextControl has a whole lot of those. I read your comments, but didn't have a chance to look through the wxEuphoria code yet.

Thanks!

- David

new topic     » goto parent     » topic index » view message » categorize

4. Re: Autogenerating wxEuphoria wrappers

OK, the prototype:

wxScrollBar(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxSB_HORIZONTAL, const wxValidator& validator = wxDefaultValidator, const wxString& name = "scrollBar")

now generates:

object WXEUAPI new_wxScrollBar(object parms)
{
int seq_len = ((s1_ptr)SEQ_PTR(parms))->length;
wxWindow parent = parent = (wxWindow*)get_int( parms, 1 );
wxWindowID id = id = (wxWindowID*)get_int( parms, 2 );
wxPoint pos = wxPoint( get_int( parms, 3 ), get_int( parms, 4 ) );
wxSize size = wxSize( get_int( parms, 5 ), get_int( parms, 6 ) );
int style = wxSB_HORIZONTAL;
if (seq_len >= 7) style = get_int( parms, 7 );
wxValidator validator = wxDefaultValidator;
if (seq_len >= 8) validator = (wxValidator*)get_int( parms, 8 );
wxString name = "scrollBar";
if (seq_len >= 9) name = get_string( parms, 9 );
wxDeRefDS( parms );
return BOX_INT( new wxScrollBar( parent, id, pos, size, style, validator, name ) );
}

So wxPoint and wxSize are automatically assumed to be integer pairs in constructors.

But I started looking through the code, and noticed how wxEuphoria handles polymorphism. In short, it doesn't seem to have a consistent approach. hit_test is a good example - the routine can be called from three different classes. So the code is basically:

object WXEUAPI hit_test( intptr_t window, int x, int y, int flags )
{
wxObject * obj = (wxObject*)window;

if ( obj->IsKindOf( CLASSINFO(wxListCtrl) ) ) {
// handle wxListCtrl

} else if ( obj->IsKindOf( CLASSINFO(wxTreeCtrl) ) ) {
// handle wxTreeCtrl

} else if ( obj->IsKindOf( CLASSINFO(wxTextCtrl) ) ) {
// handle wxTextCtrl

}

return 0;
}

In contrast, sizer_calc_min prefixes the class name to the routine to make it unique.

The first approach is fine... assuming that all the calls to different class method have the same signature. If they don't... Well, you're screwed.

Is there a scheme here that I'm not seeing?

- David

new topic     » goto parent     » topic index » view message » categorize

5. Re: Autogenerating wxEuphoria wrappers

dcuny said...

So wxPoint and wxSize are automatically assumed to be integer pairs in constructors.

That looks great. However, in the prototype you provide, pos and size are still optional, so that should probably be accounted for in the wrapper code.

wxPoint pos = wxDefaultPosition; 
if (seq_len >= 4) pos = wxPoint( get_int( parms, 3 ), get_int( parms, 4 ) ); 
 
wxSize size = wxDefaultSize; 
if (seq_len >= 6) size = wxSize( get_int( parms, 5 ), get_int( parms, 6 ) );  

dcuny said...

The first approach is fine... assuming that all the calls to different class method have the same signature. If they don't... Well, you're screwed.

Yeah, we're screwed...

                    virtual int wxBookCtrlBase::HitTest (const wxPoint &pt, long *flags=NULL) const  
virtual wxCalendarHitTestResult wxCalendarCtrl::HitTest (const wxPoint &pos, wxDateTime *date=NULL, wxDateTime::WeekDay *wd=NULL) 
                   virtual void wxDataViewCtrl::HitTest (const wxPoint &point, wxDataViewItem &item, wxDataViewColumn *&col) const  
                               long wxListCtrl::HitTest (const wxPoint &point, int &flags, long *ptrSubItem=NULL) const 
    wxPropertyGridHitTestResult wxPropertyGrid::HitTest (const wxPoint &pt) const  
            wxTextCtrlHitTestResult wxTextCtrl::HitTest (const wxPoint &pt, long *pos) const  
                       wxTreeItemId wxTreeCtrl::HitTest (const wxPoint &point, int &flags) const  

And I'm sure there are more HitTest methods I haven't found yet.

dcuny said...

Is there a scheme here that I'm not seeing?

Nope. But there needs to be. My plan is to wrap each class function discretely and then separate each class into their own include file (e.g. wx/class/wxScrollBar.e) so that we can separate functions by namespace, and then public include those from corresponding wxWidgets-style include files (e.g. wx/scrollbar.e) to better match wxWidgets coding styles. So this is where the automation comes in.

-Greg

new topic     » goto parent     » topic index » view message » categorize

6. Re: Autogenerating wxEuphoria wrappers

ghaberek said...

That looks great. However, in the prototype you provide, pos and size are still optional, so that should probably be accounted for in the wrapper code.

D'oh! sad Yes, that's easy enough to fix.

ghaberek said...

Nope. But there needs to be. My plan is to wrap each class function discretely and then separate each class into their own include file (e.g. wx/class/wxScrollBar.e) so that we can separate functions by namespace, and then public include those from corresponding wxWidgets-style include files (e.g. wx/scrollbar.e) to better match wxWidgets coding styles. So this is where the automation comes in.

Have you looked at wxBasic? There's a single .i file that holds all the information, modeled off SWIG.

Of course, you can generate as many different files from it as you like.

The class information is taken from the wxWidgets HTML file, not the .h files. That's because you'll run into some "under the hood" differences (such as support objects) that are implemented differently for different classes.

To get around the issue of constants such as:

wxCAL_SUNDAY_FIRST

you could potentially generate a C++ file filled with printf statements. That way, you wouldn't have to scrape through .h files to get the values.

If you're thinking of revamping wxEuphoria, there are a lot of questions that I've got, mostly having to do with inheritance.

- David

new topic     » goto parent     » topic index » view message » categorize

7. Re: Autogenerating wxEuphoria wrappers

dcuny said...

Have you looked at wxBasic? There's a single .i file that holds all the information, modeled off SWIG.

Where can I find the latest source code for wxBasic? It appears there are two sites: wxbasic.sourceforge.net and wxbasic.net. The files on SourceForge appear to be outdated.

dcuny said...

The class information is taken from the wxWidgets HTML file, not the .h files. That's because you'll run into some "under the hood" differences (such as support objects) that are implemented differently for different classes.

I discovered those differences as well. I had previously tried using the Doxygen XML output to a similar effect.

dcuny said...

To get around the issue of constants such as:

wxCAL_SUNDAY_FIRST

you could potentially generate a C++ file filled with printf statements. That way, you wouldn't have to scrape through .h files to get the values.

I hadn't thought of this, but that's a great idea. And the constant names can still be derived from from the parsed data.

dcuny said...

If you're thinking of revamping wxEuphoria, there are a lot of questions that I've got, mostly having to do with inheritance.

I have considered it for a long time. Development has stalled out over the past few years and I think reorganizing it will help foster future development.

Automating the wrapping process is well worth the effort to keep the entire wxEuphoria in check with the upstream wxWidgets library.

-Greg

new topic     » goto parent     » topic index » view message » categorize

8. Re: Autogenerating wxEuphoria wrappers

ghaberek said...

Where can I find the latest source code for wxBasic? It appears there are two sites: wxbasic.sourceforge.net and wxbasic.net. The files on SourceForge appear to be outdated.

The last ones I worked on are on Sourceforge, but I've not done updates for a long time. I was referring to the organization of the .i files more than anything else.

ghaberek said...

I discovered those differences as well. I had previously tried using the Doxygen XML output to a similar effect.

Yeah, it was a bit of a nasty surprise. The biggest problem is figuring out where you need to diverge and write your own versions of functions. In the end it's best to stay as close as possible.

ghaberek said...

I hadn't thought of this, but that's a great idea. And the constant names can still be derived from from the parsed data.

Yeah, I'm lazy that way. ;)

ghaberek said...

Automating the wrapping process is well worth the effort to keep the entire wxEuphoria in check with the upstream wxWidgets library.

Do you have my email address? I'd like to take this off-line to figure out what would work best for you. I'm not in a position where I'm able to take on a large project (which is why wxBasic is essentially abandoned), but I'll be happy to get this Euphoria version of SWIG to a point where it's useful to you.

But at the end of the day, it's probably easiest for you to maintain the SWIG-ish code. That way, as you find prototypes that don't match existing patterns, it's easy enough to tweak yourself instead of having to rely on someone else.

- David

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu