After banging my head against a wall for a few hours with Perl 5's XS, I
have an idea for how Parrot can do it better.

Basically, the big problems with XS are:
        -It's ugly as hell
        -It makes the extender do tons of extra work
        -It seriously munges your code

However, it has a few good features too, especially the concept of
typemaps.  (They look just as bad as the rest of XS, but the idea is
sound.)  So, how do we keep the good and rid ourselves of the bad?
Here's an example of my proposed format.

        /* optional */
        parrot_xs {
                xs_version      => 0.1,
                parrot_version  => 0.0.3
        };

        #include <math.h>

        /* not sure if we need this */
        module {
                name    => Math::Round,
                version => 1.0.3
        };

        extern int floor(double);
        extern int ciel(double);

        int round(double num) {
        int flr=floor(num);

                if(num < flr + 0.5) {
                        return flr;
                }
                else {
                        return ciel(num);
                }
        }

        /* Actually, these and a few other simple mappings would
           probably be built in, but you get the idea.           */

        typemap {
                double  {
                        type => Parrot_Float,
                        from => CAST,
                        to   => CAST
                },
                int     {
                        type => Parrot_Int,
                        from => CAST,
                        to   => CAST
                },
                char *  {
                        type => Parrot_String,
                        from => { return Parrot_string_to_chars(interpreter,
      },
                        to   => { return Parrot_string_make(interpreter, arg, 
strlen(arg)); }
                }
        };

As you can see, it's basically C with a few struct-looking things.  It's
not quite as simple as Inline::C, but it's much closer to that than Perl
5 XS.

The first struct-like thing, 'parrot_xs', does version assertions and
probably would also do some options.  (I have no idea what those options
would be, but whatever...)

The second, 'module', describes the extension.  It gives a name and a
version.  The name will probably only be needed if we mangle the opcode
names, the function names, or both.  I think we'll need it for
something, but I'm not sure.

Then come the function definitions.  Any function not declared static is
exposed, including the two extern ones.

Finally, we have the typemap.  This is the most complicated one.  It
consists of:

        FINALTYPE {
                type => TYPE,
                from => BLOCK_TO_CHANGE_FROM_TYPE_TO_FINALTYPE,
                to   => BLOCK_TO_CHANGE_FROM_FINALTYPE_TO_TYPE
        }

Basically, here's how it works:

Parrot understands five types--INTVAL, FLOATVAL, STRING*, PMC*, and a
pointer type (either void* or DPOINTER*).  It knows how to convert
between these types.

The from block is a function that's called to transform from one of
those five types to the type we actually want.  The to block converts
from the type we actually wanted to one of the five types.

If you got a PMC and wanted a char *, the actual code would look
something like this:

        TypeMap_Parrot_String_TO_char_PTR(interpreter,
pmc->vtable->get_string(interpreter, pmc));

That function would have this definition:

        char *
        TypeMap_Parrot_String_TO_char_PTR(struct Parrot_Interp *interpreter,
Parrot_String arg)
                { return Parrot_string_to_chars(interpreter, arg);          }

Note that for most extensions you won't even need a typemap.  These
three and a few others would likely be built-in.  The biggest need for
this would probably be when you're working with C structs.

The link between an extension sub and Parrot bytecode is an opcode.  The
round() opcodes would probably be like this:

        op round(out INT, in NUM) {
                $1=(INTVAL)round((FLOATVAL)$2);
                goto NEXT();
        }

        op round(out PMC, in PMC) {
                $1->vtable->set_integer(interpreter, $1,
round($2->vtable->get_number(interpreter, $2)));
        }

(Actually, those names might be mangled, as might the name for the
C-level round() function.  I'll have to figure that out.)

I'm sure other people have ideas on this.  Let 'em fly--the more the
merrier.

--Brent Dax
[EMAIL PROTECTED]
Parrot Configure pumpking, regex hacker, embedding coder, and boy genius

#define private public
    --Spotted in a C++ program just before a #include

Reply via email to